blob: 868ae291b960fd32f6054b322cdca8cd3bfad326 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <asm/io.h>
51#include <linux/delay.h>
52#include <linux/interrupt.h>
53#include <linux/init.h>
54#include <linux/slab.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010055#include <linux/mutex.h>
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <sound/core.h>
58
59#include "ice1712.h"
60#include "envy24ht.h"
61#include "aureon.h"
Takashi Iwaif640c322006-08-30 16:57:37 +020062#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010064/* AC97 register cache for Aureon */
65struct aureon_spec {
66 unsigned short stac9744[64];
67 unsigned int cs8415_mux;
68 unsigned short master[2];
69 unsigned short vol[8];
70 unsigned char pca9554_out;
71};
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073/* WM8770 registers */
74#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
75#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
76#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
77#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
78#define WM_PHASE_SWAP 0x12 /* DAC phase */
79#define WM_DAC_CTRL1 0x13 /* DAC control bits */
80#define WM_MUTE 0x14 /* mute controls */
81#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
82#define WM_INT_CTRL 0x16 /* interface control */
83#define WM_MASTER 0x17 /* master clock and mode */
84#define WM_POWERDOWN 0x18 /* power-down controls */
85#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
86#define WM_ADC_MUX 0x1b /* input MUX */
87#define WM_OUT_MUX1 0x1c /* output MUX */
88#define WM_OUT_MUX2 0x1e /* output MUX */
89#define WM_RESET 0x1f /* software reset */
90
91/* CS8415A registers */
92#define CS8415_CTRL1 0x01
93#define CS8415_CTRL2 0x02
94#define CS8415_QSUB 0x14
95#define CS8415_RATIO 0x1E
96#define CS8415_C_BUFFER 0x20
97#define CS8415_ID 0x7F
98
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +020099/* PCA9554 registers */
100#define PCA9554_DEV 0x40 /* I2C device address */
101#define PCA9554_IN 0x00 /* input port */
102#define PCA9554_OUT 0x01 /* output port */
103#define PCA9554_INVERT 0x02 /* input invert */
104#define PCA9554_DIR 0x03 /* port directions */
105
106/*
107 * Aureon Universe additional controls using PCA9554
108 */
109
110/*
111 * Send data to pca9554
112 */
113static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg,
114 unsigned char data)
115{
116 unsigned int tmp;
117 int i, j;
118 unsigned char dev = PCA9554_DEV; /* ID 0100000, write */
119 unsigned char val = 0;
120
121 tmp = snd_ice1712_gpio_read(ice);
122
123 snd_ice1712_gpio_set_mask(ice, ~(AUREON_SPI_MOSI|AUREON_SPI_CLK|
124 AUREON_WM_RW|AUREON_WM_CS|
125 AUREON_CS8415_CS));
126 tmp |= AUREON_WM_RW;
127 tmp |= AUREON_CS8415_CS | AUREON_WM_CS; /* disable SPI devices */
128
129 tmp &= ~AUREON_SPI_MOSI;
130 tmp &= ~AUREON_SPI_CLK;
131 snd_ice1712_gpio_write(ice, tmp);
132 udelay(50);
133
134 /*
135 * send i2c stop condition and start condition
136 * to obtain sane state
137 */
138 tmp |= AUREON_SPI_CLK;
139 snd_ice1712_gpio_write(ice, tmp);
140 udelay(50);
141 tmp |= AUREON_SPI_MOSI;
142 snd_ice1712_gpio_write(ice, tmp);
143 udelay(100);
144 tmp &= ~AUREON_SPI_MOSI;
145 snd_ice1712_gpio_write(ice, tmp);
146 udelay(50);
147 tmp &= ~AUREON_SPI_CLK;
148 snd_ice1712_gpio_write(ice, tmp);
149 udelay(100);
150 /*
151 * send device address, command and value,
152 * skipping ack cycles inbetween
153 */
154 for (j = 0; j < 3; j++) {
155 switch(j) {
156 case 0: val = dev; break;
157 case 1: val = reg; break;
158 case 2: val = data; break;
159 }
160 for (i = 7; i >= 0; i--) {
161 tmp &= ~AUREON_SPI_CLK;
162 snd_ice1712_gpio_write(ice, tmp);
163 udelay(40);
164 if (val & (1 << i))
165 tmp |= AUREON_SPI_MOSI;
166 else
167 tmp &= ~AUREON_SPI_MOSI;
168 snd_ice1712_gpio_write(ice, tmp);
169 udelay(40);
170 tmp |= AUREON_SPI_CLK;
171 snd_ice1712_gpio_write(ice, tmp);
172 udelay(40);
173 }
174 tmp &= ~AUREON_SPI_CLK;
175 snd_ice1712_gpio_write(ice, tmp);
176 udelay(40);
177 tmp |= AUREON_SPI_CLK;
178 snd_ice1712_gpio_write(ice, tmp);
179 udelay(40);
180 tmp &= ~AUREON_SPI_CLK;
181 snd_ice1712_gpio_write(ice, tmp);
182 udelay(40);
183 }
184 tmp &= ~AUREON_SPI_CLK;
185 snd_ice1712_gpio_write(ice, tmp);
186 udelay(40);
187 tmp &= ~AUREON_SPI_MOSI;
188 snd_ice1712_gpio_write(ice, tmp);
189 udelay(40);
190 tmp |= AUREON_SPI_CLK;
191 snd_ice1712_gpio_write(ice, tmp);
192 udelay(50);
193 tmp |= AUREON_SPI_MOSI;
194 snd_ice1712_gpio_write(ice, tmp);
195 udelay(100);
196}
197
198static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol,
199 struct snd_ctl_elem_info *uinfo)
200{
201 char *texts[3] = {"Internal Aux", "Wavetable", "Rear Line-In"};
202
203 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
204 uinfo->count = 1;
205 uinfo->value.enumerated.items = 3;
206 if(uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
207 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
208 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
209 return 0;
210}
211
212static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
213 struct snd_ctl_elem_value *ucontrol)
214{
215 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100216 struct aureon_spec *spec = ice->spec;
217 ucontrol->value.enumerated.item[0] = spec->pca9554_out;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200218 return 0;
219}
220
221static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
222 struct snd_ctl_elem_value *ucontrol)
223{
224 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100225 struct aureon_spec *spec = ice->spec;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200226 unsigned char oval, nval;
227 int change;
228
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100229 nval = ucontrol->value.enumerated.item[0];
230 if (nval >= 3)
231 return -EINVAL;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200232 snd_ice1712_save_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100233 oval = spec->pca9554_out;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200234 if ((change = (oval != nval))) {
235 aureon_pca9554_write(ice, PCA9554_OUT, nval);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100236 spec->pca9554_out = nval;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200237 }
238 snd_ice1712_restore_gpio_status(ice);
239
240 return change;
241}
242
243
244static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
245 unsigned short val)
246{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100247 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 unsigned int tmp;
249
250 /* Send address to XILINX chip */
251 tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F);
252 snd_ice1712_gpio_write(ice, tmp);
253 udelay(10);
254 tmp |= AUREON_AC97_ADDR;
255 snd_ice1712_gpio_write(ice, tmp);
256 udelay(10);
257 tmp &= ~AUREON_AC97_ADDR;
258 snd_ice1712_gpio_write(ice, tmp);
259 udelay(10);
260
261 /* Send low-order byte to XILINX chip */
262 tmp &= ~AUREON_AC97_DATA_MASK;
263 tmp |= val & AUREON_AC97_DATA_MASK;
264 snd_ice1712_gpio_write(ice, tmp);
265 udelay(10);
266 tmp |= AUREON_AC97_DATA_LOW;
267 snd_ice1712_gpio_write(ice, tmp);
268 udelay(10);
269 tmp &= ~AUREON_AC97_DATA_LOW;
270 snd_ice1712_gpio_write(ice, tmp);
271 udelay(10);
272
273 /* Send high-order byte to XILINX chip */
274 tmp &= ~AUREON_AC97_DATA_MASK;
275 tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
276
277 snd_ice1712_gpio_write(ice, tmp);
278 udelay(10);
279 tmp |= AUREON_AC97_DATA_HIGH;
280 snd_ice1712_gpio_write(ice, tmp);
281 udelay(10);
282 tmp &= ~AUREON_AC97_DATA_HIGH;
283 snd_ice1712_gpio_write(ice, tmp);
284 udelay(10);
285
286 /* Instruct XILINX chip to parse the data to the STAC9744 chip */
287 tmp |= AUREON_AC97_COMMIT;
288 snd_ice1712_gpio_write(ice, tmp);
289 udelay(10);
290 tmp &= ~AUREON_AC97_COMMIT;
291 snd_ice1712_gpio_write(ice, tmp);
292 udelay(10);
293
294 /* Store the data in out private buffer */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100295 spec->stac9744[(reg & 0x7F) >> 1] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100298static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100300 struct aureon_spec *spec = ice->spec;
301 return spec->stac9744[(reg & 0x7F) >> 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302}
303
304/*
305 * Initialize STAC9744 chip
306 */
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200307static int aureon_ac97_init (struct snd_ice1712 *ice)
308{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100309 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 int i;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100311 static const unsigned short ac97_defaults[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 0x00, 0x9640,
313 0x02, 0x8000,
314 0x04, 0x8000,
315 0x06, 0x8000,
316 0x0C, 0x8008,
317 0x0E, 0x8008,
318 0x10, 0x8808,
319 0x12, 0x8808,
320 0x14, 0x8808,
321 0x16, 0x8808,
322 0x18, 0x8808,
323 0x1C, 0x8000,
324 0x26, 0x000F,
325 0x28, 0x0201,
326 0x2C, 0xBB80,
327 0x32, 0xBB80,
328 0x7C, 0x8384,
329 0x7E, 0x7644,
330 (unsigned short)-1
331 };
332 unsigned int tmp;
333
334 /* Cold reset */
335 tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
336 snd_ice1712_gpio_write(ice, tmp);
337 udelay(3);
338
339 tmp &= ~AUREON_AC97_RESET;
340 snd_ice1712_gpio_write(ice, tmp);
341 udelay(3);
342
343 tmp |= AUREON_AC97_RESET;
344 snd_ice1712_gpio_write(ice, tmp);
345 udelay(3);
346
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100347 memset(&spec->stac9744, 0, sizeof(spec->stac9744));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100349 spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351 aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770
352
353 return 0;
354}
355
356#define AUREON_AC97_STEREO 0x80
357
358/*
359 * AC'97 volume controls
360 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100361static int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
363 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
364 uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1;
365 uinfo->value.integer.min = 0;
366 uinfo->value.integer.max = 31;
367 return 0;
368}
369
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100370static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100372 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 unsigned short vol;
374
Ingo Molnar62932df2006-01-16 16:34:20 +0100375 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
378 ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
379 if (kcontrol->private_value & AUREON_AC97_STEREO)
380 ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
381
Ingo Molnar62932df2006-01-16 16:34:20 +0100382 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 return 0;
384}
385
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100386static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100388 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 unsigned short ovol, nvol;
390 int change;
391
392 snd_ice1712_save_gpio_status(ice);
393
394 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
395 nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F;
396 if (kcontrol->private_value & AUREON_AC97_STEREO)
397 nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
398 nvol |= ovol & ~0x1F1F;
399
400 if ((change = (ovol != nvol)))
401 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
402
403 snd_ice1712_restore_gpio_status(ice);
404
405 return change;
406}
407
408/*
409 * AC'97 mute controls
410 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200411#define aureon_ac97_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100413static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100415 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Ingo Molnar62932df2006-01-16 16:34:20 +0100417 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
420
Ingo Molnar62932df2006-01-16 16:34:20 +0100421 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 return 0;
423}
424
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100425static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100427 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 unsigned short ovol, nvol;
429 int change;
430
431 snd_ice1712_save_gpio_status(ice);
432
433 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
434 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~ 0x8000);
435
436 if ((change = (ovol != nvol)))
437 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
438
439 snd_ice1712_restore_gpio_status(ice);
440
441 return change;
442}
443
444/*
445 * AC'97 mute controls
446 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200447#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100449static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100451 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Ingo Molnar62932df2006-01-16 16:34:20 +0100453 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
456
Ingo Molnar62932df2006-01-16 16:34:20 +0100457 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 return 0;
459}
460
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100461static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100463 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 unsigned short ovol, nvol;
465 int change;
466
467 snd_ice1712_save_gpio_status(ice);
468
469 ovol = aureon_ac97_read(ice, AC97_MIC);
470 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
471
472 if ((change = (ovol != nvol)))
473 aureon_ac97_write(ice, AC97_MIC, nvol);
474
475 snd_ice1712_restore_gpio_status(ice);
476
477 return change;
478}
479
480/*
481 * write data in the SPI mode
482 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100483static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 unsigned int tmp;
486 int i;
Takashi Iwai45fe7222006-01-13 13:50:16 +0100487 unsigned int mosi, clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 tmp = snd_ice1712_gpio_read(ice);
490
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100491 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
492 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100493 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
494 mosi = PRODIGY_SPI_MOSI;
495 clk = PRODIGY_SPI_CLK;
496 }
497 else {
498 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
499 AUREON_WM_CS|AUREON_CS8415_CS));
500 mosi = AUREON_SPI_MOSI;
501 clk = AUREON_SPI_CLK;
502
503 tmp |= AUREON_WM_RW;
504 }
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 tmp &= ~cs;
507 snd_ice1712_gpio_write(ice, tmp);
508 udelay(1);
509
510 for (i = bits - 1; i >= 0; i--) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100511 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 snd_ice1712_gpio_write(ice, tmp);
513 udelay(1);
514 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100515 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100517 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 snd_ice1712_gpio_write(ice, tmp);
519 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100520 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 snd_ice1712_gpio_write(ice, tmp);
522 udelay(1);
523 }
524
Takashi Iwai45fe7222006-01-13 13:50:16 +0100525 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 tmp |= cs;
527 snd_ice1712_gpio_write(ice, tmp);
528 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100529 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 snd_ice1712_gpio_write(ice, tmp);
531 udelay(1);
532}
533
534/*
535 * Read data in SPI mode
536 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100537static 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 -0700538 int i, j;
539 unsigned int tmp;
540
541 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
542 snd_ice1712_gpio_write(ice, tmp);
543 tmp &= ~cs;
544 snd_ice1712_gpio_write(ice, tmp);
545 udelay(1);
546
547 for (i=bits-1; i>=0; i--) {
548 if (data & (1 << i))
549 tmp |= AUREON_SPI_MOSI;
550 else
551 tmp &= ~AUREON_SPI_MOSI;
552 snd_ice1712_gpio_write(ice, tmp);
553 udelay(1);
554
555 tmp |= AUREON_SPI_CLK;
556 snd_ice1712_gpio_write(ice, tmp);
557 udelay(1);
558
559 tmp &= ~AUREON_SPI_CLK;
560 snd_ice1712_gpio_write(ice, tmp);
561 udelay(1);
562 }
563
564 for (j=0; j<size; j++) {
565 unsigned char outdata = 0;
566 for (i=7; i>=0; i--) {
567 tmp = snd_ice1712_gpio_read(ice);
568 outdata <<= 1;
569 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
570 udelay(1);
571
572 tmp |= AUREON_SPI_CLK;
573 snd_ice1712_gpio_write(ice, tmp);
574 udelay(1);
575
576 tmp &= ~AUREON_SPI_CLK;
577 snd_ice1712_gpio_write(ice, tmp);
578 udelay(1);
579 }
580 buffer[j] = outdata;
581 }
582
583 tmp |= cs;
584 snd_ice1712_gpio_write(ice, tmp);
585}
586
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100587static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 unsigned char val;
589 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
590 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
591 return val;
592}
593
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100594static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg, unsigned char *buffer, int size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
596 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
597}
598
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100599static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg, unsigned char val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
601}
602
603/*
604 * get the current register value of WM codec
605 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100606static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
608 reg <<= 1;
609 return ((unsigned short)ice->akm[0].images[reg] << 8) |
610 ice->akm[0].images[reg + 1];
611}
612
613/*
614 * set the register value of WM codec
615 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100616static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100618 aureon_spi_write(ice,
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100619 ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
620 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
621 PRODIGY_WM_CS : AUREON_WM_CS),
Takashi Iwai45fe7222006-01-13 13:50:16 +0100622 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623}
624
625/*
626 * set the register value of WM codec and remember it
627 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100628static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
630 wm_put_nocache(ice, reg, val);
631 reg <<= 1;
632 ice->akm[0].images[reg] = val >> 8;
633 ice->akm[0].images[reg + 1] = val;
634}
635
636/*
637 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200638#define aureon_mono_bool_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640/*
641 * AC'97 master playback mute controls (Mute on WM8770 chip)
642 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200643#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100645static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100647 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Ingo Molnar62932df2006-01-16 16:34:20 +0100649 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
652
Ingo Molnar62932df2006-01-16 16:34:20 +0100653 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 return 0;
655}
656
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100657static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
658 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 unsigned short ovol, nvol;
660 int change;
661
662 snd_ice1712_save_gpio_status(ice);
663
664 ovol = wm_get(ice, WM_OUT_MUX1);
665 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
666 if ((change = (ovol != nvol)))
667 wm_put(ice, WM_OUT_MUX1, nvol);
668
669 snd_ice1712_restore_gpio_status(ice);
670
671 return change;
672}
673
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100674static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
675static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
676static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
677static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
678static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
Takashi Iwaif640c322006-08-30 16:57:37 +0200679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680/*
681 * Logarithmic volume values for WM8770
682 * Computed as 20 * Log10(255 / x)
683 */
Takashi Iwai32b47da2007-01-29 15:26:36 +0100684static const unsigned char wm_vol[256] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
686 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
687 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
688 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
689 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
690 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,
691 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,
692 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,
693 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,
694 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,
695 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,
696 0, 0
697};
698
699#define WM_VOL_MAX (sizeof(wm_vol) - 1)
700#define WM_VOL_MUTE 0x8000
701
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100702static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 unsigned char nvol;
705
706 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
707 nvol = 0;
708 else
709 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
710
711 wm_put(ice, index, nvol);
712 wm_put_nocache(ice, index, 0x180 | nvol);
713}
714
715/*
716 * DAC mute control
717 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200718#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100720static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100722 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Ingo Molnar62932df2006-01-16 16:34:20 +0100724 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100726 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return 0;
728}
729
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100730static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100732 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 unsigned short nval, oval;
734 int change;
735
736 snd_ice1712_save_gpio_status(ice);
737 oval = wm_get(ice, WM_MUTE);
738 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
739 if ((change = (nval != oval)))
740 wm_put(ice, WM_MUTE, nval);
741 snd_ice1712_restore_gpio_status(ice);
742
743 return change;
744}
745
746/*
747 * Master volume attenuation mixer control
748 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100749static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750{
751 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
752 uinfo->count = 2;
753 uinfo->value.integer.min = 0;
754 uinfo->value.integer.max = WM_VOL_MAX;
755 return 0;
756}
757
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100758static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100760 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100761 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 int i;
763 for (i=0; i<2; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100764 ucontrol->value.integer.value[i] =
765 spec->master[i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return 0;
767}
768
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100769static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100771 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100772 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 int ch, change = 0;
774
775 snd_ice1712_save_gpio_status(ice);
776 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100777 unsigned int vol = ucontrol->value.integer.value[ch];
778 if (vol > WM_VOL_MAX)
779 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100780 vol |= spec->master[ch] & WM_VOL_MUTE;
781 if (vol != spec->master[ch]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100783 spec->master[ch] = vol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
785 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100786 spec->vol[dac + ch],
787 spec->master[ch]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 change = 1;
789 }
790 }
791 snd_ice1712_restore_gpio_status(ice);
792 return change;
793}
794
795/*
796 * DAC volume attenuation mixer control
797 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100798static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799{
800 int voices = kcontrol->private_value >> 8;
801 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
802 uinfo->count = voices;
803 uinfo->value.integer.min = 0; /* mute (-101dB) */
804 uinfo->value.integer.max = 0x7F; /* 0dB */
805 return 0;
806}
807
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100808static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100810 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100811 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 int i, ofs, voices;
813
814 voices = kcontrol->private_value >> 8;
815 ofs = kcontrol->private_value & 0xff;
816 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100817 ucontrol->value.integer.value[i] =
818 spec->vol[ofs+i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return 0;
820}
821
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100822static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100824 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100825 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 int i, idx, ofs, voices;
827 int change = 0;
828
829 voices = kcontrol->private_value >> 8;
830 ofs = kcontrol->private_value & 0xff;
831 snd_ice1712_save_gpio_status(ice);
832 for (i = 0; i < voices; i++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100833 unsigned int vol = ucontrol->value.integer.value[i];
834 if (vol > 0x7f)
835 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100836 vol |= spec->vol[ofs+i];
837 if (vol != spec->vol[ofs+i]) {
838 spec->vol[ofs+i] = vol;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100839 idx = WM_DAC_ATTEN + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100840 wm_set_vol(ice, idx, spec->vol[ofs + i],
841 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 change = 1;
843 }
844 }
845 snd_ice1712_restore_gpio_status(ice);
846 return change;
847}
848
849/*
850 * WM8770 mute control
851 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100852static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
854 uinfo->count = kcontrol->private_value >> 8;
855 uinfo->value.integer.min = 0;
856 uinfo->value.integer.max = 1;
857 return 0;
858}
859
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100860static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100862 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100863 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 int voices, ofs, i;
865
866 voices = kcontrol->private_value >> 8;
867 ofs = kcontrol->private_value & 0xFF;
868
869 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100870 ucontrol->value.integer.value[i] =
871 (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 return 0;
873}
874
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100875static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100877 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100878 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 int change = 0, voices, ofs, i;
880
881 voices = kcontrol->private_value >> 8;
882 ofs = kcontrol->private_value & 0xFF;
883
884 snd_ice1712_save_gpio_status(ice);
885 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100886 int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 if (ucontrol->value.integer.value[i] != val) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100888 spec->vol[ofs + i] &= ~WM_VOL_MUTE;
889 spec->vol[ofs + i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100891 wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
892 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 change = 1;
894 }
895 }
896 snd_ice1712_restore_gpio_status(ice);
897
898 return change;
899}
900
901/*
902 * WM8770 master mute control
903 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200904#define wm_master_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100906static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100908 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100909 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100911 ucontrol->value.integer.value[0] =
912 (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
913 ucontrol->value.integer.value[1] =
914 (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 return 0;
916}
917
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100918static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100920 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100921 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 int change = 0, i;
923
924 snd_ice1712_save_gpio_status(ice);
925 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100926 int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 if (ucontrol->value.integer.value[i] != val) {
928 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100929 spec->master[i] &= ~WM_VOL_MUTE;
930 spec->master[i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
932 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
933 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100934 spec->vol[dac + i],
935 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 change = 1;
937 }
938 }
939 snd_ice1712_restore_gpio_status(ice);
940
941 return change;
942}
943
944/* digital master volume */
945#define PCM_0dB 0xff
946#define PCM_RES 128 /* -64dB */
947#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100948static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949{
950 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
951 uinfo->count = 1;
952 uinfo->value.integer.min = 0; /* mute (-64dB) */
953 uinfo->value.integer.max = PCM_RES; /* 0dB */
954 return 0;
955}
956
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100957static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100959 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 unsigned short val;
961
Ingo Molnar62932df2006-01-16 16:34:20 +0100962 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
964 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
965 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100966 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 return 0;
968}
969
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100970static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100972 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 unsigned short ovol, nvol;
974 int change = 0;
975
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100977 if (nvol > PCM_RES)
978 return -EINVAL;
979 snd_ice1712_save_gpio_status(ice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
981 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
982 if (ovol != nvol) {
983 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
984 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
985 change = 1;
986 }
987 snd_ice1712_restore_gpio_status(ice);
988 return change;
989}
990
991/*
992 * ADC mute control
993 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200994#define wm_adc_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100996static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100998 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 unsigned short val;
1000 int i;
1001
Ingo Molnar62932df2006-01-16 16:34:20 +01001002 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 for (i = 0; i < 2; i++) {
1004 val = wm_get(ice, WM_ADC_GAIN + i);
1005 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
1006 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001007 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 return 0;
1009}
1010
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001011static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001013 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 unsigned short new, old;
1015 int i, change = 0;
1016
1017 snd_ice1712_save_gpio_status(ice);
1018 for (i = 0; i < 2; i++) {
1019 old = wm_get(ice, WM_ADC_GAIN + i);
1020 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
1021 if (new != old) {
1022 wm_put(ice, WM_ADC_GAIN + i, new);
1023 change = 1;
1024 }
1025 }
1026 snd_ice1712_restore_gpio_status(ice);
1027
1028 return change;
1029}
1030
1031/*
1032 * ADC gain mixer control
1033 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001034static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035{
1036 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1037 uinfo->count = 2;
1038 uinfo->value.integer.min = 0; /* -12dB */
1039 uinfo->value.integer.max = 0x1f; /* 19dB */
1040 return 0;
1041}
1042
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001043static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001045 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 int i, idx;
1047 unsigned short vol;
1048
Ingo Molnar62932df2006-01-16 16:34:20 +01001049 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 for (i = 0; i < 2; i++) {
1051 idx = WM_ADC_GAIN + i;
1052 vol = wm_get(ice, idx) & 0x1f;
1053 ucontrol->value.integer.value[i] = vol;
1054 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001055 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 return 0;
1057}
1058
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001059static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001061 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 int i, idx;
1063 unsigned short ovol, nvol;
1064 int change = 0;
1065
1066 snd_ice1712_save_gpio_status(ice);
1067 for (i = 0; i < 2; i++) {
1068 idx = WM_ADC_GAIN + i;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +01001069 nvol = ucontrol->value.integer.value[i] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 ovol = wm_get(ice, idx);
1071 if ((ovol & 0x1f) != nvol) {
1072 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1073 change = 1;
1074 }
1075 }
1076 snd_ice1712_restore_gpio_status(ice);
1077 return change;
1078}
1079
1080/*
1081 * ADC input mux mixer control
1082 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001083static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001085 static const char * const texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 "CD", //AIN1
1087 "Aux", //AIN2
1088 "Line", //AIN3
1089 "Mic", //AIN4
1090 "AC97" //AIN5
1091 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001092 static const char * const universe_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 "Aux1", //AIN1
1094 "CD", //AIN2
1095 "Phono", //AIN3
1096 "Line", //AIN4
1097 "Aux2", //AIN5
1098 "Mic", //AIN6
1099 "Aux3", //AIN7
1100 "AC97" //AIN8
1101 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001102 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1105 uinfo->count = 2;
1106 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1107 uinfo->value.enumerated.items = 8;
1108 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1109 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1110 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
1111 }
1112 else {
1113 uinfo->value.enumerated.items = 5;
1114 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1115 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1116 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1117 }
1118 return 0;
1119}
1120
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001121static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001123 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 unsigned short val;
1125
Ingo Molnar62932df2006-01-16 16:34:20 +01001126 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001128 ucontrol->value.enumerated.item[0] = val & 7;
1129 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001130 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 return 0;
1132}
1133
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001134static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001136 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 unsigned short oval, nval;
1138 int change;
1139
1140 snd_ice1712_save_gpio_status(ice);
1141 oval = wm_get(ice, WM_ADC_MUX);
1142 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001143 nval |= ucontrol->value.enumerated.item[0] & 7;
1144 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 change = (oval != nval);
1146 if (change)
1147 wm_put(ice, WM_ADC_MUX, nval);
1148 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001149 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150}
1151
1152/*
1153 * CS8415 Input mux
1154 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001155static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001157 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai32b47da2007-01-29 15:26:36 +01001158 static const char * const aureon_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 "CD", //RXP0
1160 "Optical" //RXP1
1161 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001162 static const char * const prodigy_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 "CD",
1164 "Coax"
1165 };
1166 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1167 uinfo->count = 1;
1168 uinfo->value.enumerated.items = 2;
1169 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1170 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1171 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1172 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1173 else
1174 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1175 return 0;
1176}
1177
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001178static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001180 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001181 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
1183 //snd_ice1712_save_gpio_status(ice);
1184 //val = aureon_cs8415_get(ice, CS8415_CTRL2);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001185 ucontrol->value.enumerated.item[0] = spec->cs8415_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 //snd_ice1712_restore_gpio_status(ice);
1187 return 0;
1188}
1189
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001190static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001192 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001193 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 unsigned short oval, nval;
1195 int change;
1196
1197 snd_ice1712_save_gpio_status(ice);
1198 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1199 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001200 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 change = (oval != nval);
1202 if (change)
1203 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1204 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001205 spec->cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 return change;
1207}
1208
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001209static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210{
1211 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1212 uinfo->count = 1;
1213 uinfo->value.integer.min = 0;
1214 uinfo->value.integer.max = 192000;
1215 return 0;
1216}
1217
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001218static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001220 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 unsigned char ratio;
1222 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1223 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1224 return 0;
1225}
1226
1227/*
1228 * CS8415A Mute
1229 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001230#define aureon_cs8415_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001232static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001234 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 snd_ice1712_save_gpio_status(ice);
1236 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1237 snd_ice1712_restore_gpio_status(ice);
1238 return 0;
1239}
1240
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001241static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001243 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 unsigned char oval, nval;
1245 int change;
1246 snd_ice1712_save_gpio_status(ice);
1247 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1248 if (ucontrol->value.integer.value[0])
1249 nval = oval & ~0x20;
1250 else
1251 nval = oval | 0x20;
1252 if ((change = (oval != nval)))
1253 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1254 snd_ice1712_restore_gpio_status(ice);
1255 return change;
1256}
1257
1258/*
1259 * CS8415A Q-Sub info
1260 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001261static int aureon_cs8415_qsub_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1263 uinfo->count = 10;
1264 return 0;
1265}
1266
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001267static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1268 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 snd_ice1712_save_gpio_status(ice);
1271 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1272 snd_ice1712_restore_gpio_status(ice);
1273
1274 return 0;
1275}
1276
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001277static int aureon_cs8415_spdif_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1279 uinfo->count = 1;
1280 return 0;
1281}
1282
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001283static int aureon_cs8415_mask_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 memset(ucontrol->value.iec958.status, 0xFF, 24);
1285 return 0;
1286}
1287
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001288static int aureon_cs8415_spdif_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1289 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
1291 snd_ice1712_save_gpio_status(ice);
1292 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1293 snd_ice1712_restore_gpio_status(ice);
1294 return 0;
1295}
1296
1297/*
1298 * Headphone Amplifier
1299 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001300static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301{
1302 unsigned int tmp, tmp2;
1303
1304 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1305 if (enable)
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001306 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1307 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001308 tmp |= AUREON_HP_SEL;
1309 else
1310 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 else
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001312 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1313 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001314 tmp &= ~ AUREON_HP_SEL;
1315 else
1316 tmp &= ~ PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (tmp != tmp2) {
1318 snd_ice1712_gpio_write(ice, tmp);
1319 return 1;
1320 }
1321 return 0;
1322}
1323
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001324static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325{
1326 unsigned int tmp = snd_ice1712_gpio_read(ice);
1327
1328 return ( tmp & AUREON_HP_SEL )!= 0;
1329}
1330
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001331#define aureon_hpamp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001333static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001335 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1338 return 0;
1339}
1340
1341
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001342static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001344 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
1347}
1348
1349/*
1350 * Deemphasis
1351 */
1352
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001353#define aureon_deemp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001355static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001357 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1359 return 0;
1360}
1361
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001362static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001364 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 int temp, temp2;
1366 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1367 if (ucontrol->value.integer.value[0])
1368 temp |= 0xf;
1369 else
1370 temp &= ~0xf;
1371 if (temp != temp2) {
1372 wm_put(ice, WM_DAC_CTRL2, temp);
1373 return 1;
1374 }
1375 return 0;
1376}
1377
1378/*
1379 * ADC Oversampling
1380 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001381static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001383 static const char * const texts[2] = { "128x", "64x" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
1385 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1386 uinfo->count = 1;
1387 uinfo->value.enumerated.items = 2;
1388
1389 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1390 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1391 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1392
1393 return 0;
1394}
1395
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001396static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001398 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1400 return 0;
1401}
1402
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001403static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404{
1405 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001406 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
1408 temp2 = temp = wm_get(ice, WM_MASTER);
1409
1410 if (ucontrol->value.enumerated.item[0])
1411 temp |= 0x8;
1412 else
1413 temp &= ~0x8;
1414
1415 if (temp != temp2) {
1416 wm_put(ice, WM_MASTER, temp);
1417 return 1;
1418 }
1419 return 0;
1420}
1421
1422/*
1423 * mixers
1424 */
1425
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001426static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 {
1428 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1429 .name = "Master Playback Switch",
1430 .info = wm_master_mute_info,
1431 .get = wm_master_mute_get,
1432 .put = wm_master_mute_put
1433 },
1434 {
1435 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001436 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1437 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 .name = "Master Playback Volume",
1439 .info = wm_master_vol_info,
1440 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001441 .put = wm_master_vol_put,
1442 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 },
1444 {
1445 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1446 .name = "Front Playback Switch",
1447 .info = wm_mute_info,
1448 .get = wm_mute_get,
1449 .put = wm_mute_put,
1450 .private_value = (2 << 8) | 0
1451 },
1452 {
1453 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001454 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1455 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 .name = "Front Playback Volume",
1457 .info = wm_vol_info,
1458 .get = wm_vol_get,
1459 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001460 .private_value = (2 << 8) | 0,
1461 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 },
1463 {
1464 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1465 .name = "Rear Playback Switch",
1466 .info = wm_mute_info,
1467 .get = wm_mute_get,
1468 .put = wm_mute_put,
1469 .private_value = (2 << 8) | 2
1470 },
1471 {
1472 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001473 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1474 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 .name = "Rear Playback Volume",
1476 .info = wm_vol_info,
1477 .get = wm_vol_get,
1478 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001479 .private_value = (2 << 8) | 2,
1480 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 },
1482 {
1483 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1484 .name = "Center Playback Switch",
1485 .info = wm_mute_info,
1486 .get = wm_mute_get,
1487 .put = wm_mute_put,
1488 .private_value = (1 << 8) | 4
1489 },
1490 {
1491 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001492 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1493 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 .name = "Center Playback Volume",
1495 .info = wm_vol_info,
1496 .get = wm_vol_get,
1497 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001498 .private_value = (1 << 8) | 4,
1499 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 },
1501 {
1502 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1503 .name = "LFE Playback Switch",
1504 .info = wm_mute_info,
1505 .get = wm_mute_get,
1506 .put = wm_mute_put,
1507 .private_value = (1 << 8) | 5
1508 },
1509 {
1510 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001511 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1512 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 .name = "LFE Playback Volume",
1514 .info = wm_vol_info,
1515 .get = wm_vol_get,
1516 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001517 .private_value = (1 << 8) | 5,
1518 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 },
1520 {
1521 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1522 .name = "Side Playback Switch",
1523 .info = wm_mute_info,
1524 .get = wm_mute_get,
1525 .put = wm_mute_put,
1526 .private_value = (2 << 8) | 6
1527 },
1528 {
1529 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001530 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1531 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 .name = "Side Playback Volume",
1533 .info = wm_vol_info,
1534 .get = wm_vol_get,
1535 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001536 .private_value = (2 << 8) | 6,
1537 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 }
1539};
1540
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001541static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 {
1543 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1544 .name = "PCM Playback Switch",
1545 .info = wm_pcm_mute_info,
1546 .get = wm_pcm_mute_get,
1547 .put = wm_pcm_mute_put
1548 },
1549 {
1550 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001551 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1552 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 .name = "PCM Playback Volume",
1554 .info = wm_pcm_vol_info,
1555 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001556 .put = wm_pcm_vol_put,
1557 .tlv = { .p = db_scale_wm_pcm }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 },
1559 {
1560 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1561 .name = "Capture Switch",
1562 .info = wm_adc_mute_info,
1563 .get = wm_adc_mute_get,
1564 .put = wm_adc_mute_put,
1565 },
1566 {
1567 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001568 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1569 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 .name = "Capture Volume",
1571 .info = wm_adc_vol_info,
1572 .get = wm_adc_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001573 .put = wm_adc_vol_put,
1574 .tlv = { .p = db_scale_wm_adc }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 },
1576 {
1577 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1578 .name = "Capture Source",
1579 .info = wm_adc_mux_info,
1580 .get = wm_adc_mux_get,
1581 .put = wm_adc_mux_put,
1582 .private_value = 5
1583 },
1584 {
1585 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1586 .name = "External Amplifier",
1587 .info = aureon_hpamp_info,
1588 .get = aureon_hpamp_get,
1589 .put = aureon_hpamp_put
1590 },
1591 {
1592 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1593 .name = "DAC Deemphasis Switch",
1594 .info = aureon_deemp_info,
1595 .get = aureon_deemp_get,
1596 .put = aureon_deemp_put
1597 },
1598 {
1599 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1600 .name = "ADC Oversampling",
1601 .info = aureon_oversampling_info,
1602 .get = aureon_oversampling_get,
1603 .put = aureon_oversampling_put
1604 }
1605};
1606
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001607static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 {
1609 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1610 .name = "AC97 Playback Switch",
1611 .info = aureon_ac97_mmute_info,
1612 .get = aureon_ac97_mmute_get,
1613 .put = aureon_ac97_mmute_put,
1614 .private_value = AC97_MASTER
1615 },
1616 {
1617 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001618 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1619 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 .name = "AC97 Playback Volume",
1621 .info = aureon_ac97_vol_info,
1622 .get = aureon_ac97_vol_get,
1623 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001624 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1625 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 },
1627 {
1628 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1629 .name = "CD Playback Switch",
1630 .info = aureon_ac97_mute_info,
1631 .get = aureon_ac97_mute_get,
1632 .put = aureon_ac97_mute_put,
1633 .private_value = AC97_CD
1634 },
1635 {
1636 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001637 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1638 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 .name = "CD Playback Volume",
1640 .info = aureon_ac97_vol_info,
1641 .get = aureon_ac97_vol_get,
1642 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001643 .private_value = AC97_CD|AUREON_AC97_STEREO,
1644 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 },
1646 {
1647 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1648 .name = "Aux Playback Switch",
1649 .info = aureon_ac97_mute_info,
1650 .get = aureon_ac97_mute_get,
1651 .put = aureon_ac97_mute_put,
1652 .private_value = AC97_AUX,
1653 },
1654 {
1655 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001656 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1657 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 .name = "Aux Playback Volume",
1659 .info = aureon_ac97_vol_info,
1660 .get = aureon_ac97_vol_get,
1661 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001662 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1663 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 },
1665 {
1666 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1667 .name = "Line Playback Switch",
1668 .info = aureon_ac97_mute_info,
1669 .get = aureon_ac97_mute_get,
1670 .put = aureon_ac97_mute_put,
1671 .private_value = AC97_LINE
1672 },
1673 {
1674 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001675 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1676 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 .name = "Line Playback Volume",
1678 .info = aureon_ac97_vol_info,
1679 .get = aureon_ac97_vol_get,
1680 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001681 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1682 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 },
1684 {
1685 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1686 .name = "Mic Playback Switch",
1687 .info = aureon_ac97_mute_info,
1688 .get = aureon_ac97_mute_get,
1689 .put = aureon_ac97_mute_put,
1690 .private_value = AC97_MIC
1691 },
1692 {
1693 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001694 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1695 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 .name = "Mic Playback Volume",
1697 .info = aureon_ac97_vol_info,
1698 .get = aureon_ac97_vol_get,
1699 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001700 .private_value = AC97_MIC,
1701 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 },
1703 {
1704 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1705 .name = "Mic Boost (+20dB)",
1706 .info = aureon_ac97_micboost_info,
1707 .get = aureon_ac97_micboost_get,
1708 .put = aureon_ac97_micboost_put
1709 }
1710};
1711
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001712static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 {
1714 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1715 .name = "AC97 Playback Switch",
1716 .info = aureon_ac97_mmute_info,
1717 .get = aureon_ac97_mmute_get,
1718 .put = aureon_ac97_mmute_put,
1719 .private_value = AC97_MASTER
1720 },
1721 {
1722 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001723 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1724 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 .name = "AC97 Playback Volume",
1726 .info = aureon_ac97_vol_info,
1727 .get = aureon_ac97_vol_get,
1728 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001729 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1730 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 },
1732 {
1733 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1734 .name = "CD Playback Switch",
1735 .info = aureon_ac97_mute_info,
1736 .get = aureon_ac97_mute_get,
1737 .put = aureon_ac97_mute_put,
1738 .private_value = AC97_AUX
1739 },
1740 {
1741 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001742 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1743 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 .name = "CD Playback Volume",
1745 .info = aureon_ac97_vol_info,
1746 .get = aureon_ac97_vol_get,
1747 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001748 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1749 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 },
1751 {
1752 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1753 .name = "Phono Playback Switch",
1754 .info = aureon_ac97_mute_info,
1755 .get = aureon_ac97_mute_get,
1756 .put = aureon_ac97_mute_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001757 .private_value = AC97_CD
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 },
1759 {
1760 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001761 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1762 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 .name = "Phono Playback Volume",
1764 .info = aureon_ac97_vol_info,
1765 .get = aureon_ac97_vol_get,
1766 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001767 .private_value = AC97_CD|AUREON_AC97_STEREO,
1768 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 },
1770 {
1771 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1772 .name = "Line Playback Switch",
1773 .info = aureon_ac97_mute_info,
1774 .get = aureon_ac97_mute_get,
1775 .put = aureon_ac97_mute_put,
1776 .private_value = AC97_LINE
1777 },
1778 {
1779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001780 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1781 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 .name = "Line Playback Volume",
1783 .info = aureon_ac97_vol_info,
1784 .get = aureon_ac97_vol_get,
1785 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001786 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1787 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 },
1789 {
1790 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1791 .name = "Mic Playback Switch",
1792 .info = aureon_ac97_mute_info,
1793 .get = aureon_ac97_mute_get,
1794 .put = aureon_ac97_mute_put,
1795 .private_value = AC97_MIC
1796 },
1797 {
1798 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001799 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1800 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 .name = "Mic Playback Volume",
1802 .info = aureon_ac97_vol_info,
1803 .get = aureon_ac97_vol_get,
1804 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001805 .private_value = AC97_MIC,
1806 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 },
1808 {
1809 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1810 .name = "Mic Boost (+20dB)",
1811 .info = aureon_ac97_micboost_info,
1812 .get = aureon_ac97_micboost_get,
1813 .put = aureon_ac97_micboost_put
1814 },
1815 {
1816 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1817 .name = "Aux Playback Switch",
1818 .info = aureon_ac97_mute_info,
1819 .get = aureon_ac97_mute_get,
1820 .put = aureon_ac97_mute_put,
1821 .private_value = AC97_VIDEO,
1822 },
1823 {
1824 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001825 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1826 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 .name = "Aux Playback Volume",
1828 .info = aureon_ac97_vol_info,
1829 .get = aureon_ac97_vol_get,
1830 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001831 .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
1832 .tlv = { .p = db_scale_ac97_gain }
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001833 },
1834 {
1835 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1836 .name = "Aux Source",
1837 .info = aureon_universe_inmux_info,
1838 .get = aureon_universe_inmux_get,
1839 .put = aureon_universe_inmux_put
1840 }
1841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842};
1843
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001844static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 {
1846 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1847 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
1848 .info = aureon_cs8415_mute_info,
1849 .get = aureon_cs8415_mute_get,
1850 .put = aureon_cs8415_mute_put
1851 },
1852 {
1853 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1854 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Source",
1855 .info = aureon_cs8415_mux_info,
1856 .get = aureon_cs8415_mux_get,
1857 .put = aureon_cs8415_mux_put,
1858 },
1859 {
1860 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1861 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ",CAPTURE,DEFAULT),
1862 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1863 .info = aureon_cs8415_qsub_info,
1864 .get = aureon_cs8415_qsub_get,
1865 },
1866 {
1867 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1868 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
1869 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1870 .info = aureon_cs8415_spdif_info,
1871 .get = aureon_cs8415_mask_get
1872 },
1873 {
1874 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1875 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
1876 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1877 .info = aureon_cs8415_spdif_info,
1878 .get = aureon_cs8415_spdif_get
1879 },
1880 {
1881 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1882 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Rate",
1883 .access =SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1884 .info = aureon_cs8415_rate_info,
1885 .get = aureon_cs8415_rate_get
1886 }
1887};
1888
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001889static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890{
1891 unsigned int i, counts;
1892 int err;
1893
1894 counts = ARRAY_SIZE(aureon_dac_controls);
1895 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1896 counts -= 2; /* no side */
1897 for (i = 0; i < counts; i++) {
1898 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1899 if (err < 0)
1900 return err;
1901 }
1902
1903 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1904 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1905 if (err < 0)
1906 return err;
1907 }
1908
1909 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1910 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1911 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1912 if (err < 0)
1913 return err;
1914 }
1915 }
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001916 else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1917 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1919 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1920 if (err < 0)
1921 return err;
1922 }
1923 }
1924
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001925 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1926 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 unsigned char id;
1928 snd_ice1712_save_gpio_status(ice);
1929 id = aureon_cs8415_get(ice, CS8415_ID);
1930 if (id != 0x41)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001931 snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 else if ((id & 0x0F) != 0x01)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001933 snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 else {
1935 for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001936 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1938 if (err < 0)
1939 return err;
1940 if (i > 1)
1941 kctl->id.device = ice->pcm->device;
1942 }
1943 }
1944 snd_ice1712_restore_gpio_status(ice);
1945 }
1946
1947 return 0;
1948}
1949
1950
1951/*
1952 * initialize the chip
1953 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001954static int __devinit aureon_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001956 static const unsigned short wm_inits_aureon[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 /* These come first to reduce init pop noise */
1958 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1959 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1960 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1961
1962 0x18, 0x000, /* All power-up */
1963
1964 0x16, 0x122, /* I2S, normal polarity, 24bit */
1965 0x17, 0x022, /* 256fs, slave mode */
1966 0x00, 0, /* DAC1 analog mute */
1967 0x01, 0, /* DAC2 analog mute */
1968 0x02, 0, /* DAC3 analog mute */
1969 0x03, 0, /* DAC4 analog mute */
1970 0x04, 0, /* DAC5 analog mute */
1971 0x05, 0, /* DAC6 analog mute */
1972 0x06, 0, /* DAC7 analog mute */
1973 0x07, 0, /* DAC8 analog mute */
1974 0x08, 0x100, /* master analog mute */
1975 0x09, 0xff, /* DAC1 digital full */
1976 0x0a, 0xff, /* DAC2 digital full */
1977 0x0b, 0xff, /* DAC3 digital full */
1978 0x0c, 0xff, /* DAC4 digital full */
1979 0x0d, 0xff, /* DAC5 digital full */
1980 0x0e, 0xff, /* DAC6 digital full */
1981 0x0f, 0xff, /* DAC7 digital full */
1982 0x10, 0xff, /* DAC8 digital full */
1983 0x11, 0x1ff, /* master digital full */
1984 0x12, 0x000, /* phase normal */
1985 0x13, 0x090, /* unmute DAC L/R */
1986 0x14, 0x000, /* all unmute */
1987 0x15, 0x000, /* no deemphasis, no ZFLG */
1988 0x19, 0x000, /* -12dB ADC/L */
1989 0x1a, 0x000, /* -12dB ADC/R */
1990 (unsigned short)-1
1991 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001992 static const unsigned short wm_inits_prodigy[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
1994 /* These come first to reduce init pop noise */
1995 0x1b, 0x000, /* ADC Mux */
1996 0x1c, 0x009, /* Out Mux1 */
1997 0x1d, 0x009, /* Out Mux2 */
1998
1999 0x18, 0x000, /* All power-up */
2000
2001 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
2002 0x17, 0x006, /* 128fs, slave mode */
2003
2004 0x00, 0, /* DAC1 analog mute */
2005 0x01, 0, /* DAC2 analog mute */
2006 0x02, 0, /* DAC3 analog mute */
2007 0x03, 0, /* DAC4 analog mute */
2008 0x04, 0, /* DAC5 analog mute */
2009 0x05, 0, /* DAC6 analog mute */
2010 0x06, 0, /* DAC7 analog mute */
2011 0x07, 0, /* DAC8 analog mute */
2012 0x08, 0x100, /* master analog mute */
2013
2014 0x09, 0x7f, /* DAC1 digital full */
2015 0x0a, 0x7f, /* DAC2 digital full */
2016 0x0b, 0x7f, /* DAC3 digital full */
2017 0x0c, 0x7f, /* DAC4 digital full */
2018 0x0d, 0x7f, /* DAC5 digital full */
2019 0x0e, 0x7f, /* DAC6 digital full */
2020 0x0f, 0x7f, /* DAC7 digital full */
2021 0x10, 0x7f, /* DAC8 digital full */
2022 0x11, 0x1FF, /* master digital full */
2023
2024 0x12, 0x000, /* phase normal */
2025 0x13, 0x090, /* unmute DAC L/R */
2026 0x14, 0x000, /* all unmute */
2027 0x15, 0x000, /* no deemphasis, no ZFLG */
2028
2029 0x19, 0x000, /* -12dB ADC/L */
2030 0x1a, 0x000, /* -12dB ADC/R */
2031 (unsigned short)-1
2032
2033 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01002034 static const unsigned short cs_inits[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 0x0441, /* RUN */
2036 0x0180, /* no mute, OMCK output on RMCK pin */
2037 0x0201, /* S/PDIF source on RXP1 */
2038 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
2039 (unsigned short)-1
2040 };
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002041 struct aureon_spec *spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 unsigned int tmp;
Takashi Iwai32b47da2007-01-29 15:26:36 +01002043 const unsigned short *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 int err, i;
2045
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002046 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2047 if (!spec)
2048 return -ENOMEM;
2049 ice->spec = spec;
2050
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
2052 ice->num_total_dacs = 6;
2053 ice->num_total_adcs = 2;
2054 } else {
2055 /* aureon 7.1 and prodigy 7.1 */
2056 ice->num_total_dacs = 8;
2057 ice->num_total_adcs = 2;
2058 }
2059
2060 /* to remeber the register values of CS8415 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01002061 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if (! ice->akm)
2063 return -ENOMEM;
2064 ice->akm_codecs = 1;
2065
2066 if ((err = aureon_ac97_init(ice)) != 0)
2067 return err;
2068
2069 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
2070
2071 /* reset the wm codec as the SPI mode */
2072 snd_ice1712_save_gpio_status(ice);
2073 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
2074
2075 tmp = snd_ice1712_gpio_read(ice);
2076 tmp &= ~AUREON_WM_RESET;
2077 snd_ice1712_gpio_write(ice, tmp);
2078 udelay(1);
2079 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
2080 snd_ice1712_gpio_write(ice, tmp);
2081 udelay(1);
2082 tmp |= AUREON_WM_RESET;
2083 snd_ice1712_gpio_write(ice, tmp);
2084 udelay(1);
2085
2086 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002087 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002088 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
2089 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 p = wm_inits_prodigy;
2091 else
2092 p = wm_inits_aureon;
2093 for (; *p != (unsigned short)-1; p += 2)
2094 wm_put(ice, p[0], p[1]);
2095
2096 /* initialize CS8415A codec */
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002097 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
2098 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +01002099 for (p = cs_inits; *p != (unsigned short)-1; p++)
2100 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002101 spec->cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
Takashi Iwai45fe7222006-01-13 13:50:16 +01002103 aureon_set_headphone_amp(ice, 1);
2104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
2106 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002107
2108 /* initialize PCA9554 pin directions & set default input*/
2109 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2110 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002112 spec->master[0] = WM_VOL_MUTE;
2113 spec->master[1] = WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 for (i = 0; i < ice->num_total_dacs; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002115 spec->vol[i] = WM_VOL_MUTE;
2116 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 }
2118
2119 return 0;
2120}
2121
2122
2123/*
2124 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2125 * hence the driver needs to sets up it properly.
2126 */
2127
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002128static unsigned char aureon51_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002129 [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
2130 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2131 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2132 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2133 [ICE_EEP2_GPIO_DIR] = 0xff,
2134 [ICE_EEP2_GPIO_DIR1] = 0xff,
2135 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2136 [ICE_EEP2_GPIO_MASK] = 0x00,
2137 [ICE_EEP2_GPIO_MASK1] = 0x00,
2138 [ICE_EEP2_GPIO_MASK2] = 0x00,
2139 [ICE_EEP2_GPIO_STATE] = 0x00,
2140 [ICE_EEP2_GPIO_STATE1] = 0x00,
2141 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142};
2143
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002144static unsigned char aureon71_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002145 [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
2146 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2147 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2148 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2149 [ICE_EEP2_GPIO_DIR] = 0xff,
2150 [ICE_EEP2_GPIO_DIR1] = 0xff,
2151 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2152 [ICE_EEP2_GPIO_MASK] = 0x00,
2153 [ICE_EEP2_GPIO_MASK1] = 0x00,
2154 [ICE_EEP2_GPIO_MASK2] = 0x00,
2155 [ICE_EEP2_GPIO_STATE] = 0x00,
2156 [ICE_EEP2_GPIO_STATE1] = 0x00,
2157 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158};
Takashi Iwai189bc172007-01-29 15:25:40 +01002159#define prodigy71_eeprom aureon71_eeprom
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002161static unsigned char prodigy71lt_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002162 [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
2163 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2164 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2165 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2166 [ICE_EEP2_GPIO_DIR] = 0xff,
2167 [ICE_EEP2_GPIO_DIR1] = 0xff,
2168 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2169 [ICE_EEP2_GPIO_MASK] = 0x00,
2170 [ICE_EEP2_GPIO_MASK1] = 0x00,
2171 [ICE_EEP2_GPIO_MASK2] = 0x00,
2172 [ICE_EEP2_GPIO_STATE] = 0x00,
2173 [ICE_EEP2_GPIO_STATE1] = 0x00,
2174 [ICE_EEP2_GPIO_STATE2] = 0x00,
Takashi Iwai45fe7222006-01-13 13:50:16 +01002175};
Takashi Iwai189bc172007-01-29 15:25:40 +01002176#define prodigy71xt_eeprom prodigy71lt_eeprom
Takashi Iwai45fe7222006-01-13 13:50:16 +01002177
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178/* entry point */
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002179struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 {
2181 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2182 .name = "Terratec Aureon 5.1-Sky",
2183 .model = "aureon51",
2184 .chip_init = aureon_init,
2185 .build_controls = aureon_add_controls,
2186 .eeprom_size = sizeof(aureon51_eeprom),
2187 .eeprom_data = aureon51_eeprom,
2188 .driver = "Aureon51",
2189 },
2190 {
2191 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2192 .name = "Terratec Aureon 7.1-Space",
2193 .model = "aureon71",
2194 .chip_init = aureon_init,
2195 .build_controls = aureon_add_controls,
2196 .eeprom_size = sizeof(aureon71_eeprom),
2197 .eeprom_data = aureon71_eeprom,
2198 .driver = "Aureon71",
2199 },
2200 {
2201 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2202 .name = "Terratec Aureon 7.1-Universe",
2203 .model = "universe",
2204 .chip_init = aureon_init,
2205 .build_controls = aureon_add_controls,
2206 .eeprom_size = sizeof(aureon71_eeprom),
2207 .eeprom_data = aureon71_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002208 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 },
2210 {
2211 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2212 .name = "Audiotrak Prodigy 7.1",
2213 .model = "prodigy71",
2214 .chip_init = aureon_init,
2215 .build_controls = aureon_add_controls,
2216 .eeprom_size = sizeof(prodigy71_eeprom),
2217 .eeprom_data = prodigy71_eeprom,
2218 .driver = "Prodigy71", /* should be identical with Aureon71 */
2219 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002220 {
2221 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2222 .name = "Audiotrak Prodigy 7.1 LT",
2223 .model = "prodigy71lt",
2224 .chip_init = aureon_init,
2225 .build_controls = aureon_add_controls,
2226 .eeprom_size = sizeof(prodigy71lt_eeprom),
2227 .eeprom_data = prodigy71lt_eeprom,
2228 .driver = "Prodigy71LT",
2229 },
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002230 {
2231 .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
2232 .name = "Audiotrak Prodigy 7.1 XT",
2233 .model = "prodigy71xt",
2234 .chip_init = aureon_init,
2235 .build_controls = aureon_add_controls,
2236 .eeprom_size = sizeof(prodigy71xt_eeprom),
2237 .eeprom_data = prodigy71xt_eeprom,
2238 .driver = "Prodigy71LT",
2239 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 { } /* terminator */
2241};