blob: 0f7f4d8263c0eb1d186b095f928daaa7407f7bb2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ALSA driver for ICEnsemble VT1724 (Envy24HT)
3 *
4 * Lowlevel functions for Terratec Aureon cards
5 *
6 * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 *
23 * NOTES:
24 *
Takashi Iwaiab0c7d72005-11-17 15:00:18 +010025 * - we reuse the struct snd_akm4xxx record for storing the wm8770 codec data.
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 * both wm and akm codecs are pretty similar, so we can integrate
27 * both controls in the future, once if wm codecs are reused in
28 * many boards.
29 *
30 * - DAC digital volumes are not implemented in the mixer.
31 * if they show better response than DAC analog volumes, we can use them
32 * instead.
33 *
34 * Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards
35 * Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca>
36 *
37 * version 0.82: Stable / not all features work yet (no communication with AC97 secondary)
38 * added 64x/128x oversampling switch (should be 64x only for 96khz)
39 * fixed some recording labels (still need to check the rest)
40 * recording is working probably thanks to correct wm8770 initialization
41 *
42 * version 0.5: Initial release:
43 * working: analog output, mixer, headphone amplifier switch
44 * not working: prety much everything else, at least i could verify that
45 * we have no digital output, no capture, pretty bad clicks and poops
46 * on mixer switch and other coll stuff.
47 *
48 */
49
50#include <sound/driver.h>
51#include <asm/io.h>
52#include <linux/delay.h>
53#include <linux/interrupt.h>
54#include <linux/init.h>
55#include <linux/slab.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010056#include <linux/mutex.h>
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <sound/core.h>
59
60#include "ice1712.h"
61#include "envy24ht.h"
62#include "aureon.h"
63
64/* WM8770 registers */
65#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
66#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
67#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
68#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
69#define WM_PHASE_SWAP 0x12 /* DAC phase */
70#define WM_DAC_CTRL1 0x13 /* DAC control bits */
71#define WM_MUTE 0x14 /* mute controls */
72#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
73#define WM_INT_CTRL 0x16 /* interface control */
74#define WM_MASTER 0x17 /* master clock and mode */
75#define WM_POWERDOWN 0x18 /* power-down controls */
76#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
77#define WM_ADC_MUX 0x1b /* input MUX */
78#define WM_OUT_MUX1 0x1c /* output MUX */
79#define WM_OUT_MUX2 0x1e /* output MUX */
80#define WM_RESET 0x1f /* software reset */
81
82/* CS8415A registers */
83#define CS8415_CTRL1 0x01
84#define CS8415_CTRL2 0x02
85#define CS8415_QSUB 0x14
86#define CS8415_RATIO 0x1E
87#define CS8415_C_BUFFER 0x20
88#define CS8415_ID 0x7F
89
Takashi Iwaiab0c7d72005-11-17 15:00:18 +010090static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, unsigned short val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 unsigned int tmp;
92
93 /* Send address to XILINX chip */
94 tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F);
95 snd_ice1712_gpio_write(ice, tmp);
96 udelay(10);
97 tmp |= AUREON_AC97_ADDR;
98 snd_ice1712_gpio_write(ice, tmp);
99 udelay(10);
100 tmp &= ~AUREON_AC97_ADDR;
101 snd_ice1712_gpio_write(ice, tmp);
102 udelay(10);
103
104 /* Send low-order byte to XILINX chip */
105 tmp &= ~AUREON_AC97_DATA_MASK;
106 tmp |= val & AUREON_AC97_DATA_MASK;
107 snd_ice1712_gpio_write(ice, tmp);
108 udelay(10);
109 tmp |= AUREON_AC97_DATA_LOW;
110 snd_ice1712_gpio_write(ice, tmp);
111 udelay(10);
112 tmp &= ~AUREON_AC97_DATA_LOW;
113 snd_ice1712_gpio_write(ice, tmp);
114 udelay(10);
115
116 /* Send high-order byte to XILINX chip */
117 tmp &= ~AUREON_AC97_DATA_MASK;
118 tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
119
120 snd_ice1712_gpio_write(ice, tmp);
121 udelay(10);
122 tmp |= AUREON_AC97_DATA_HIGH;
123 snd_ice1712_gpio_write(ice, tmp);
124 udelay(10);
125 tmp &= ~AUREON_AC97_DATA_HIGH;
126 snd_ice1712_gpio_write(ice, tmp);
127 udelay(10);
128
129 /* Instruct XILINX chip to parse the data to the STAC9744 chip */
130 tmp |= AUREON_AC97_COMMIT;
131 snd_ice1712_gpio_write(ice, tmp);
132 udelay(10);
133 tmp &= ~AUREON_AC97_COMMIT;
134 snd_ice1712_gpio_write(ice, tmp);
135 udelay(10);
136
137 /* Store the data in out private buffer */
138 ice->spec.aureon.stac9744[(reg & 0x7F) >> 1] = val;
139}
140
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100141static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
143 return ice->spec.aureon.stac9744[(reg & 0x7F) >> 1];
144}
145
146/*
147 * Initialize STAC9744 chip
148 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100149static int aureon_ac97_init (struct snd_ice1712 *ice) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 int i;
151 static unsigned short ac97_defaults[] = {
152 0x00, 0x9640,
153 0x02, 0x8000,
154 0x04, 0x8000,
155 0x06, 0x8000,
156 0x0C, 0x8008,
157 0x0E, 0x8008,
158 0x10, 0x8808,
159 0x12, 0x8808,
160 0x14, 0x8808,
161 0x16, 0x8808,
162 0x18, 0x8808,
163 0x1C, 0x8000,
164 0x26, 0x000F,
165 0x28, 0x0201,
166 0x2C, 0xBB80,
167 0x32, 0xBB80,
168 0x7C, 0x8384,
169 0x7E, 0x7644,
170 (unsigned short)-1
171 };
172 unsigned int tmp;
173
174 /* Cold reset */
175 tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
176 snd_ice1712_gpio_write(ice, tmp);
177 udelay(3);
178
179 tmp &= ~AUREON_AC97_RESET;
180 snd_ice1712_gpio_write(ice, tmp);
181 udelay(3);
182
183 tmp |= AUREON_AC97_RESET;
184 snd_ice1712_gpio_write(ice, tmp);
185 udelay(3);
186
187 memset(&ice->spec.aureon.stac9744, 0, sizeof(ice->spec.aureon.stac9744));
188 for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2)
189 ice->spec.aureon.stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
190
191 aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770
192
193 return 0;
194}
195
196#define AUREON_AC97_STEREO 0x80
197
198/*
199 * AC'97 volume controls
200 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100201static int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
203 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
204 uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1;
205 uinfo->value.integer.min = 0;
206 uinfo->value.integer.max = 31;
207 return 0;
208}
209
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100210static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100212 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 unsigned short vol;
214
Ingo Molnar62932df2006-01-16 16:34:20 +0100215 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
218 ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
219 if (kcontrol->private_value & AUREON_AC97_STEREO)
220 ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
221
Ingo Molnar62932df2006-01-16 16:34:20 +0100222 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 return 0;
224}
225
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100226static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100228 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 unsigned short ovol, nvol;
230 int change;
231
232 snd_ice1712_save_gpio_status(ice);
233
234 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
235 nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F;
236 if (kcontrol->private_value & AUREON_AC97_STEREO)
237 nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
238 nvol |= ovol & ~0x1F1F;
239
240 if ((change = (ovol != nvol)))
241 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
242
243 snd_ice1712_restore_gpio_status(ice);
244
245 return change;
246}
247
248/*
249 * AC'97 mute controls
250 */
251#define aureon_ac97_mute_info aureon_mono_bool_info
252
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100253static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100255 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Ingo Molnar62932df2006-01-16 16:34:20 +0100257 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
259 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
260
Ingo Molnar62932df2006-01-16 16:34:20 +0100261 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 return 0;
263}
264
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100265static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100267 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 unsigned short ovol, nvol;
269 int change;
270
271 snd_ice1712_save_gpio_status(ice);
272
273 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
274 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~ 0x8000);
275
276 if ((change = (ovol != nvol)))
277 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
278
279 snd_ice1712_restore_gpio_status(ice);
280
281 return change;
282}
283
284/*
285 * AC'97 mute controls
286 */
287#define aureon_ac97_micboost_info aureon_mono_bool_info
288
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100289static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100291 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Ingo Molnar62932df2006-01-16 16:34:20 +0100293 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
296
Ingo Molnar62932df2006-01-16 16:34:20 +0100297 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 return 0;
299}
300
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100301static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100303 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 unsigned short ovol, nvol;
305 int change;
306
307 snd_ice1712_save_gpio_status(ice);
308
309 ovol = aureon_ac97_read(ice, AC97_MIC);
310 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
311
312 if ((change = (ovol != nvol)))
313 aureon_ac97_write(ice, AC97_MIC, nvol);
314
315 snd_ice1712_restore_gpio_status(ice);
316
317 return change;
318}
319
320/*
321 * write data in the SPI mode
322 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100323static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
325 unsigned int tmp;
326 int i;
Takashi Iwai45fe7222006-01-13 13:50:16 +0100327 unsigned int mosi, clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 tmp = snd_ice1712_gpio_read(ice);
330
Takashi Iwai45fe7222006-01-13 13:50:16 +0100331 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) {
332 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
333 mosi = PRODIGY_SPI_MOSI;
334 clk = PRODIGY_SPI_CLK;
335 }
336 else {
337 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
338 AUREON_WM_CS|AUREON_CS8415_CS));
339 mosi = AUREON_SPI_MOSI;
340 clk = AUREON_SPI_CLK;
341
342 tmp |= AUREON_WM_RW;
343 }
344
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 tmp &= ~cs;
346 snd_ice1712_gpio_write(ice, tmp);
347 udelay(1);
348
349 for (i = bits - 1; i >= 0; i--) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100350 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 snd_ice1712_gpio_write(ice, tmp);
352 udelay(1);
353 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100354 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100356 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 snd_ice1712_gpio_write(ice, tmp);
358 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100359 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 snd_ice1712_gpio_write(ice, tmp);
361 udelay(1);
362 }
363
Takashi Iwai45fe7222006-01-13 13:50:16 +0100364 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 tmp |= cs;
366 snd_ice1712_gpio_write(ice, tmp);
367 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100368 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 snd_ice1712_gpio_write(ice, tmp);
370 udelay(1);
371}
372
373/*
374 * Read data in SPI mode
375 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100376static 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 -0700377 int i, j;
378 unsigned int tmp;
379
380 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
381 snd_ice1712_gpio_write(ice, tmp);
382 tmp &= ~cs;
383 snd_ice1712_gpio_write(ice, tmp);
384 udelay(1);
385
386 for (i=bits-1; i>=0; i--) {
387 if (data & (1 << i))
388 tmp |= AUREON_SPI_MOSI;
389 else
390 tmp &= ~AUREON_SPI_MOSI;
391 snd_ice1712_gpio_write(ice, tmp);
392 udelay(1);
393
394 tmp |= AUREON_SPI_CLK;
395 snd_ice1712_gpio_write(ice, tmp);
396 udelay(1);
397
398 tmp &= ~AUREON_SPI_CLK;
399 snd_ice1712_gpio_write(ice, tmp);
400 udelay(1);
401 }
402
403 for (j=0; j<size; j++) {
404 unsigned char outdata = 0;
405 for (i=7; i>=0; i--) {
406 tmp = snd_ice1712_gpio_read(ice);
407 outdata <<= 1;
408 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
409 udelay(1);
410
411 tmp |= AUREON_SPI_CLK;
412 snd_ice1712_gpio_write(ice, tmp);
413 udelay(1);
414
415 tmp &= ~AUREON_SPI_CLK;
416 snd_ice1712_gpio_write(ice, tmp);
417 udelay(1);
418 }
419 buffer[j] = outdata;
420 }
421
422 tmp |= cs;
423 snd_ice1712_gpio_write(ice, tmp);
424}
425
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100426static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 unsigned char val;
428 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
429 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
430 return val;
431}
432
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100433static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg, unsigned char *buffer, int size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
435 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
436}
437
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100438static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg, unsigned char val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
440}
441
442/*
443 * get the current register value of WM codec
444 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100445static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
447 reg <<= 1;
448 return ((unsigned short)ice->akm[0].images[reg] << 8) |
449 ice->akm[0].images[reg + 1];
450}
451
452/*
453 * set the register value of WM codec
454 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100455static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100457 aureon_spi_write(ice,
458 (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS),
459 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
462/*
463 * set the register value of WM codec and remember it
464 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100465static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
467 wm_put_nocache(ice, reg, val);
468 reg <<= 1;
469 ice->akm[0].images[reg] = val >> 8;
470 ice->akm[0].images[reg + 1] = val;
471}
472
473/*
474 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100475static int aureon_mono_bool_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
477 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
478 uinfo->count = 1;
479 uinfo->value.integer.min = 0;
480 uinfo->value.integer.max = 1;
481 return 0;
482}
483
484/*
485 * AC'97 master playback mute controls (Mute on WM8770 chip)
486 */
487#define aureon_ac97_mmute_info aureon_mono_bool_info
488
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100489static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100491 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Ingo Molnar62932df2006-01-16 16:34:20 +0100493 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
496
Ingo Molnar62932df2006-01-16 16:34:20 +0100497 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return 0;
499}
500
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100501static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
502 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 unsigned short ovol, nvol;
504 int change;
505
506 snd_ice1712_save_gpio_status(ice);
507
508 ovol = wm_get(ice, WM_OUT_MUX1);
509 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
510 if ((change = (ovol != nvol)))
511 wm_put(ice, WM_OUT_MUX1, nvol);
512
513 snd_ice1712_restore_gpio_status(ice);
514
515 return change;
516}
517
518/*
519 * Logarithmic volume values for WM8770
520 * Computed as 20 * Log10(255 / x)
521 */
522static unsigned char wm_vol[256] = {
523 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
524 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
525 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
526 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
527 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
528 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,
529 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,
530 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,
531 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,
532 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,
533 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,
534 0, 0
535};
536
537#define WM_VOL_MAX (sizeof(wm_vol) - 1)
538#define WM_VOL_MUTE 0x8000
539
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100540static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
542 unsigned char nvol;
543
544 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
545 nvol = 0;
546 else
547 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
548
549 wm_put(ice, index, nvol);
550 wm_put_nocache(ice, index, 0x180 | nvol);
551}
552
553/*
554 * DAC mute control
555 */
556#define wm_pcm_mute_info aureon_mono_bool_info
557
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100558static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100560 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Ingo Molnar62932df2006-01-16 16:34:20 +0100562 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100564 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 return 0;
566}
567
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100568static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100570 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 unsigned short nval, oval;
572 int change;
573
574 snd_ice1712_save_gpio_status(ice);
575 oval = wm_get(ice, WM_MUTE);
576 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
577 if ((change = (nval != oval)))
578 wm_put(ice, WM_MUTE, nval);
579 snd_ice1712_restore_gpio_status(ice);
580
581 return change;
582}
583
584/*
585 * Master volume attenuation mixer control
586 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100587static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
589 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
590 uinfo->count = 2;
591 uinfo->value.integer.min = 0;
592 uinfo->value.integer.max = WM_VOL_MAX;
593 return 0;
594}
595
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100596static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100598 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 int i;
600 for (i=0; i<2; i++)
601 ucontrol->value.integer.value[i] = ice->spec.aureon.master[i] & ~WM_VOL_MUTE;
602 return 0;
603}
604
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100605static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100607 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 int ch, change = 0;
609
610 snd_ice1712_save_gpio_status(ice);
611 for (ch = 0; ch < 2; ch++) {
612 if (ucontrol->value.integer.value[ch] != ice->spec.aureon.master[ch]) {
613 int dac;
614 ice->spec.aureon.master[ch] &= WM_VOL_MUTE;
615 ice->spec.aureon.master[ch] |= ucontrol->value.integer.value[ch];
616 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
617 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
618 ice->spec.aureon.vol[dac + ch],
619 ice->spec.aureon.master[ch]);
620 change = 1;
621 }
622 }
623 snd_ice1712_restore_gpio_status(ice);
624 return change;
625}
626
627/*
628 * DAC volume attenuation mixer control
629 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100630static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
632 int voices = kcontrol->private_value >> 8;
633 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
634 uinfo->count = voices;
635 uinfo->value.integer.min = 0; /* mute (-101dB) */
636 uinfo->value.integer.max = 0x7F; /* 0dB */
637 return 0;
638}
639
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100640static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100642 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 int i, ofs, voices;
644
645 voices = kcontrol->private_value >> 8;
646 ofs = kcontrol->private_value & 0xff;
647 for (i = 0; i < voices; i++)
648 ucontrol->value.integer.value[i] = ice->spec.aureon.vol[ofs+i] & ~WM_VOL_MUTE;
649 return 0;
650}
651
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100652static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100654 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 int i, idx, ofs, voices;
656 int change = 0;
657
658 voices = kcontrol->private_value >> 8;
659 ofs = kcontrol->private_value & 0xff;
660 snd_ice1712_save_gpio_status(ice);
661 for (i = 0; i < voices; i++) {
662 idx = WM_DAC_ATTEN + ofs + i;
663 if (ucontrol->value.integer.value[i] != ice->spec.aureon.vol[ofs+i]) {
664 ice->spec.aureon.vol[ofs+i] &= WM_VOL_MUTE;
665 ice->spec.aureon.vol[ofs+i] |= ucontrol->value.integer.value[i];
666 wm_set_vol(ice, idx, ice->spec.aureon.vol[ofs+i],
667 ice->spec.aureon.master[i]);
668 change = 1;
669 }
670 }
671 snd_ice1712_restore_gpio_status(ice);
672 return change;
673}
674
675/*
676 * WM8770 mute control
677 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100678static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
680 uinfo->count = kcontrol->private_value >> 8;
681 uinfo->value.integer.min = 0;
682 uinfo->value.integer.max = 1;
683 return 0;
684}
685
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100686static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100688 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 int voices, ofs, i;
690
691 voices = kcontrol->private_value >> 8;
692 ofs = kcontrol->private_value & 0xFF;
693
694 for (i = 0; i < voices; i++)
695 ucontrol->value.integer.value[i] = (ice->spec.aureon.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
696 return 0;
697}
698
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100699static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100701 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 int change = 0, voices, ofs, i;
703
704 voices = kcontrol->private_value >> 8;
705 ofs = kcontrol->private_value & 0xFF;
706
707 snd_ice1712_save_gpio_status(ice);
708 for (i = 0; i < voices; i++) {
709 int val = (ice->spec.aureon.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
710 if (ucontrol->value.integer.value[i] != val) {
711 ice->spec.aureon.vol[ofs + i] &= ~WM_VOL_MUTE;
712 ice->spec.aureon.vol[ofs + i] |=
713 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
714 wm_set_vol(ice, ofs + i, ice->spec.aureon.vol[ofs + i],
715 ice->spec.aureon.master[i]);
716 change = 1;
717 }
718 }
719 snd_ice1712_restore_gpio_status(ice);
720
721 return change;
722}
723
724/*
725 * WM8770 master mute control
726 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100727static int wm_master_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
729 uinfo->count = 2;
730 uinfo->value.integer.min = 0;
731 uinfo->value.integer.max = 1;
732 return 0;
733}
734
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100735static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100737 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 ucontrol->value.integer.value[0] = (ice->spec.aureon.master[0] & WM_VOL_MUTE) ? 0 : 1;
740 ucontrol->value.integer.value[1] = (ice->spec.aureon.master[1] & WM_VOL_MUTE) ? 0 : 1;
741 return 0;
742}
743
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100744static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100746 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 int change = 0, i;
748
749 snd_ice1712_save_gpio_status(ice);
750 for (i = 0; i < 2; i++) {
751 int val = (ice->spec.aureon.master[i] & WM_VOL_MUTE) ? 0 : 1;
752 if (ucontrol->value.integer.value[i] != val) {
753 int dac;
754 ice->spec.aureon.master[i] &= ~WM_VOL_MUTE;
755 ice->spec.aureon.master[i] |=
756 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
757 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
758 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
759 ice->spec.aureon.vol[dac + i],
760 ice->spec.aureon.master[i]);
761 change = 1;
762 }
763 }
764 snd_ice1712_restore_gpio_status(ice);
765
766 return change;
767}
768
769/* digital master volume */
770#define PCM_0dB 0xff
771#define PCM_RES 128 /* -64dB */
772#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100773static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
775 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
776 uinfo->count = 1;
777 uinfo->value.integer.min = 0; /* mute (-64dB) */
778 uinfo->value.integer.max = PCM_RES; /* 0dB */
779 return 0;
780}
781
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100782static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100784 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 unsigned short val;
786
Ingo Molnar62932df2006-01-16 16:34:20 +0100787 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
789 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
790 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100791 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 return 0;
793}
794
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100795static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100797 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 unsigned short ovol, nvol;
799 int change = 0;
800
801 snd_ice1712_save_gpio_status(ice);
802 nvol = ucontrol->value.integer.value[0];
803 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
804 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
805 if (ovol != nvol) {
806 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
807 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
808 change = 1;
809 }
810 snd_ice1712_restore_gpio_status(ice);
811 return change;
812}
813
814/*
815 * ADC mute control
816 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100817static int wm_adc_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
819 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
820 uinfo->count = 2;
821 uinfo->value.integer.min = 0;
822 uinfo->value.integer.max = 1;
823 return 0;
824}
825
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100826static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100828 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 unsigned short val;
830 int i;
831
Ingo Molnar62932df2006-01-16 16:34:20 +0100832 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 for (i = 0; i < 2; i++) {
834 val = wm_get(ice, WM_ADC_GAIN + i);
835 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
836 }
Ingo Molnar62932df2006-01-16 16:34:20 +0100837 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 return 0;
839}
840
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100841static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100843 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 unsigned short new, old;
845 int i, change = 0;
846
847 snd_ice1712_save_gpio_status(ice);
848 for (i = 0; i < 2; i++) {
849 old = wm_get(ice, WM_ADC_GAIN + i);
850 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
851 if (new != old) {
852 wm_put(ice, WM_ADC_GAIN + i, new);
853 change = 1;
854 }
855 }
856 snd_ice1712_restore_gpio_status(ice);
857
858 return change;
859}
860
861/*
862 * ADC gain mixer control
863 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100864static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
866 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
867 uinfo->count = 2;
868 uinfo->value.integer.min = 0; /* -12dB */
869 uinfo->value.integer.max = 0x1f; /* 19dB */
870 return 0;
871}
872
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100873static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100875 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 int i, idx;
877 unsigned short vol;
878
Ingo Molnar62932df2006-01-16 16:34:20 +0100879 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 for (i = 0; i < 2; i++) {
881 idx = WM_ADC_GAIN + i;
882 vol = wm_get(ice, idx) & 0x1f;
883 ucontrol->value.integer.value[i] = vol;
884 }
Ingo Molnar62932df2006-01-16 16:34:20 +0100885 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return 0;
887}
888
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100889static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100891 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 int i, idx;
893 unsigned short ovol, nvol;
894 int change = 0;
895
896 snd_ice1712_save_gpio_status(ice);
897 for (i = 0; i < 2; i++) {
898 idx = WM_ADC_GAIN + i;
899 nvol = ucontrol->value.integer.value[i];
900 ovol = wm_get(ice, idx);
901 if ((ovol & 0x1f) != nvol) {
902 wm_put(ice, idx, nvol | (ovol & ~0x1f));
903 change = 1;
904 }
905 }
906 snd_ice1712_restore_gpio_status(ice);
907 return change;
908}
909
910/*
911 * ADC input mux mixer control
912 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100913static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914{
915 static char *texts[] = {
916 "CD", //AIN1
917 "Aux", //AIN2
918 "Line", //AIN3
919 "Mic", //AIN4
920 "AC97" //AIN5
921 };
922 static char *universe_texts[] = {
923 "Aux1", //AIN1
924 "CD", //AIN2
925 "Phono", //AIN3
926 "Line", //AIN4
927 "Aux2", //AIN5
928 "Mic", //AIN6
929 "Aux3", //AIN7
930 "AC97" //AIN8
931 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100932 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
934 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
935 uinfo->count = 2;
936 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
937 uinfo->value.enumerated.items = 8;
938 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
939 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
940 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
941 }
942 else {
943 uinfo->value.enumerated.items = 5;
944 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
945 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
946 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
947 }
948 return 0;
949}
950
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100951static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100953 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 unsigned short val;
955
Ingo Molnar62932df2006-01-16 16:34:20 +0100956 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 val = wm_get(ice, WM_ADC_MUX);
958 ucontrol->value.integer.value[0] = val & 7;
959 ucontrol->value.integer.value[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +0100960 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 return 0;
962}
963
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100964static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100966 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 unsigned short oval, nval;
968 int change;
969
970 snd_ice1712_save_gpio_status(ice);
971 oval = wm_get(ice, WM_ADC_MUX);
972 nval = oval & ~0x77;
973 nval |= ucontrol->value.integer.value[0] & 7;
974 nval |= (ucontrol->value.integer.value[1] & 7) << 4;
975 change = (oval != nval);
976 if (change)
977 wm_put(ice, WM_ADC_MUX, nval);
978 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +0100979 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
981
982/*
983 * CS8415 Input mux
984 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100985static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100987 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 static char *aureon_texts[] = {
989 "CD", //RXP0
990 "Optical" //RXP1
991 };
992 static char *prodigy_texts[] = {
993 "CD",
994 "Coax"
995 };
996 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
997 uinfo->count = 1;
998 uinfo->value.enumerated.items = 2;
999 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1000 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1001 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1002 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1003 else
1004 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1005 return 0;
1006}
1007
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001008static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001010 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 //snd_ice1712_save_gpio_status(ice);
1013 //val = aureon_cs8415_get(ice, CS8415_CTRL2);
1014 ucontrol->value.integer.value[0] = ice->spec.aureon.cs8415_mux;
1015 //snd_ice1712_restore_gpio_status(ice);
1016 return 0;
1017}
1018
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001019static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001021 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 unsigned short oval, nval;
1023 int change;
1024
1025 snd_ice1712_save_gpio_status(ice);
1026 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1027 nval = oval & ~0x07;
1028 nval |= ucontrol->value.integer.value[0] & 7;
1029 change = (oval != nval);
1030 if (change)
1031 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1032 snd_ice1712_restore_gpio_status(ice);
1033 ice->spec.aureon.cs8415_mux = ucontrol->value.integer.value[0];
1034 return change;
1035}
1036
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001037static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038{
1039 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1040 uinfo->count = 1;
1041 uinfo->value.integer.min = 0;
1042 uinfo->value.integer.max = 192000;
1043 return 0;
1044}
1045
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001046static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001048 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 unsigned char ratio;
1050 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1051 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1052 return 0;
1053}
1054
1055/*
1056 * CS8415A Mute
1057 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001058static int aureon_cs8415_mute_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
1060 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1061 uinfo->count = 1;
1062 return 0;
1063}
1064
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001065static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001067 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 snd_ice1712_save_gpio_status(ice);
1069 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1070 snd_ice1712_restore_gpio_status(ice);
1071 return 0;
1072}
1073
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001074static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001076 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 unsigned char oval, nval;
1078 int change;
1079 snd_ice1712_save_gpio_status(ice);
1080 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1081 if (ucontrol->value.integer.value[0])
1082 nval = oval & ~0x20;
1083 else
1084 nval = oval | 0x20;
1085 if ((change = (oval != nval)))
1086 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1087 snd_ice1712_restore_gpio_status(ice);
1088 return change;
1089}
1090
1091/*
1092 * CS8415A Q-Sub info
1093 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001094static int aureon_cs8415_qsub_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1096 uinfo->count = 10;
1097 return 0;
1098}
1099
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001100static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1101 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103 snd_ice1712_save_gpio_status(ice);
1104 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1105 snd_ice1712_restore_gpio_status(ice);
1106
1107 return 0;
1108}
1109
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001110static int aureon_cs8415_spdif_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1112 uinfo->count = 1;
1113 return 0;
1114}
1115
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001116static int aureon_cs8415_mask_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 memset(ucontrol->value.iec958.status, 0xFF, 24);
1118 return 0;
1119}
1120
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001121static int aureon_cs8415_spdif_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1122 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
1124 snd_ice1712_save_gpio_status(ice);
1125 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1126 snd_ice1712_restore_gpio_status(ice);
1127 return 0;
1128}
1129
1130/*
1131 * Headphone Amplifier
1132 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001133static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
1135 unsigned int tmp, tmp2;
1136
1137 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1138 if (enable)
1139 tmp |= AUREON_HP_SEL;
1140 else
1141 tmp &= ~ AUREON_HP_SEL;
1142 if (tmp != tmp2) {
1143 snd_ice1712_gpio_write(ice, tmp);
1144 return 1;
1145 }
1146 return 0;
1147}
1148
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001149static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150{
1151 unsigned int tmp = snd_ice1712_gpio_read(ice);
1152
1153 return ( tmp & AUREON_HP_SEL )!= 0;
1154}
1155
1156#define aureon_hpamp_info aureon_mono_bool_info
1157
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001158static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001160 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
1162 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1163 return 0;
1164}
1165
1166
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001167static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001169 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
1171 return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
1172}
1173
1174/*
1175 * Deemphasis
1176 */
1177
1178#define aureon_deemp_info aureon_mono_bool_info
1179
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001180static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001182 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1184 return 0;
1185}
1186
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001187static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001189 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 int temp, temp2;
1191 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1192 if (ucontrol->value.integer.value[0])
1193 temp |= 0xf;
1194 else
1195 temp &= ~0xf;
1196 if (temp != temp2) {
1197 wm_put(ice, WM_DAC_CTRL2, temp);
1198 return 1;
1199 }
1200 return 0;
1201}
1202
1203/*
1204 * ADC Oversampling
1205 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001206static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207{
1208 static char *texts[2] = { "128x", "64x" };
1209
1210 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1211 uinfo->count = 1;
1212 uinfo->value.enumerated.items = 2;
1213
1214 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1215 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1216 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1217
1218 return 0;
1219}
1220
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001221static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001223 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1225 return 0;
1226}
1227
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001228static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229{
1230 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001231 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 temp2 = temp = wm_get(ice, WM_MASTER);
1234
1235 if (ucontrol->value.enumerated.item[0])
1236 temp |= 0x8;
1237 else
1238 temp &= ~0x8;
1239
1240 if (temp != temp2) {
1241 wm_put(ice, WM_MASTER, temp);
1242 return 1;
1243 }
1244 return 0;
1245}
1246
1247/*
1248 * mixers
1249 */
1250
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001251static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 {
1253 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1254 .name = "Master Playback Switch",
1255 .info = wm_master_mute_info,
1256 .get = wm_master_mute_get,
1257 .put = wm_master_mute_put
1258 },
1259 {
1260 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1261 .name = "Master Playback Volume",
1262 .info = wm_master_vol_info,
1263 .get = wm_master_vol_get,
1264 .put = wm_master_vol_put
1265 },
1266 {
1267 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1268 .name = "Front Playback Switch",
1269 .info = wm_mute_info,
1270 .get = wm_mute_get,
1271 .put = wm_mute_put,
1272 .private_value = (2 << 8) | 0
1273 },
1274 {
1275 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1276 .name = "Front Playback Volume",
1277 .info = wm_vol_info,
1278 .get = wm_vol_get,
1279 .put = wm_vol_put,
1280 .private_value = (2 << 8) | 0
1281 },
1282 {
1283 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1284 .name = "Rear Playback Switch",
1285 .info = wm_mute_info,
1286 .get = wm_mute_get,
1287 .put = wm_mute_put,
1288 .private_value = (2 << 8) | 2
1289 },
1290 {
1291 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1292 .name = "Rear Playback Volume",
1293 .info = wm_vol_info,
1294 .get = wm_vol_get,
1295 .put = wm_vol_put,
1296 .private_value = (2 << 8) | 2
1297 },
1298 {
1299 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1300 .name = "Center Playback Switch",
1301 .info = wm_mute_info,
1302 .get = wm_mute_get,
1303 .put = wm_mute_put,
1304 .private_value = (1 << 8) | 4
1305 },
1306 {
1307 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1308 .name = "Center Playback Volume",
1309 .info = wm_vol_info,
1310 .get = wm_vol_get,
1311 .put = wm_vol_put,
1312 .private_value = (1 << 8) | 4
1313 },
1314 {
1315 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1316 .name = "LFE Playback Switch",
1317 .info = wm_mute_info,
1318 .get = wm_mute_get,
1319 .put = wm_mute_put,
1320 .private_value = (1 << 8) | 5
1321 },
1322 {
1323 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1324 .name = "LFE Playback Volume",
1325 .info = wm_vol_info,
1326 .get = wm_vol_get,
1327 .put = wm_vol_put,
1328 .private_value = (1 << 8) | 5
1329 },
1330 {
1331 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1332 .name = "Side Playback Switch",
1333 .info = wm_mute_info,
1334 .get = wm_mute_get,
1335 .put = wm_mute_put,
1336 .private_value = (2 << 8) | 6
1337 },
1338 {
1339 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1340 .name = "Side Playback Volume",
1341 .info = wm_vol_info,
1342 .get = wm_vol_get,
1343 .put = wm_vol_put,
1344 .private_value = (2 << 8) | 6
1345 }
1346};
1347
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001348static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 {
1350 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1351 .name = "PCM Playback Switch",
1352 .info = wm_pcm_mute_info,
1353 .get = wm_pcm_mute_get,
1354 .put = wm_pcm_mute_put
1355 },
1356 {
1357 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1358 .name = "PCM Playback Volume",
1359 .info = wm_pcm_vol_info,
1360 .get = wm_pcm_vol_get,
1361 .put = wm_pcm_vol_put
1362 },
1363 {
1364 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1365 .name = "Capture Switch",
1366 .info = wm_adc_mute_info,
1367 .get = wm_adc_mute_get,
1368 .put = wm_adc_mute_put,
1369 },
1370 {
1371 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1372 .name = "Capture Volume",
1373 .info = wm_adc_vol_info,
1374 .get = wm_adc_vol_get,
1375 .put = wm_adc_vol_put
1376 },
1377 {
1378 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1379 .name = "Capture Source",
1380 .info = wm_adc_mux_info,
1381 .get = wm_adc_mux_get,
1382 .put = wm_adc_mux_put,
1383 .private_value = 5
1384 },
1385 {
1386 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1387 .name = "External Amplifier",
1388 .info = aureon_hpamp_info,
1389 .get = aureon_hpamp_get,
1390 .put = aureon_hpamp_put
1391 },
1392 {
1393 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1394 .name = "DAC Deemphasis Switch",
1395 .info = aureon_deemp_info,
1396 .get = aureon_deemp_get,
1397 .put = aureon_deemp_put
1398 },
1399 {
1400 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1401 .name = "ADC Oversampling",
1402 .info = aureon_oversampling_info,
1403 .get = aureon_oversampling_get,
1404 .put = aureon_oversampling_put
1405 }
1406};
1407
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001408static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 {
1410 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1411 .name = "AC97 Playback Switch",
1412 .info = aureon_ac97_mmute_info,
1413 .get = aureon_ac97_mmute_get,
1414 .put = aureon_ac97_mmute_put,
1415 .private_value = AC97_MASTER
1416 },
1417 {
1418 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1419 .name = "AC97 Playback Volume",
1420 .info = aureon_ac97_vol_info,
1421 .get = aureon_ac97_vol_get,
1422 .put = aureon_ac97_vol_put,
1423 .private_value = AC97_MASTER|AUREON_AC97_STEREO
1424 },
1425 {
1426 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1427 .name = "CD Playback Switch",
1428 .info = aureon_ac97_mute_info,
1429 .get = aureon_ac97_mute_get,
1430 .put = aureon_ac97_mute_put,
1431 .private_value = AC97_CD
1432 },
1433 {
1434 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1435 .name = "CD Playback Volume",
1436 .info = aureon_ac97_vol_info,
1437 .get = aureon_ac97_vol_get,
1438 .put = aureon_ac97_vol_put,
1439 .private_value = AC97_CD|AUREON_AC97_STEREO
1440 },
1441 {
1442 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1443 .name = "Aux Playback Switch",
1444 .info = aureon_ac97_mute_info,
1445 .get = aureon_ac97_mute_get,
1446 .put = aureon_ac97_mute_put,
1447 .private_value = AC97_AUX,
1448 },
1449 {
1450 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1451 .name = "Aux Playback Volume",
1452 .info = aureon_ac97_vol_info,
1453 .get = aureon_ac97_vol_get,
1454 .put = aureon_ac97_vol_put,
1455 .private_value = AC97_AUX|AUREON_AC97_STEREO
1456 },
1457 {
1458 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1459 .name = "Line Playback Switch",
1460 .info = aureon_ac97_mute_info,
1461 .get = aureon_ac97_mute_get,
1462 .put = aureon_ac97_mute_put,
1463 .private_value = AC97_LINE
1464 },
1465 {
1466 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1467 .name = "Line Playback Volume",
1468 .info = aureon_ac97_vol_info,
1469 .get = aureon_ac97_vol_get,
1470 .put = aureon_ac97_vol_put,
1471 .private_value = AC97_LINE|AUREON_AC97_STEREO
1472 },
1473 {
1474 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1475 .name = "Mic Playback Switch",
1476 .info = aureon_ac97_mute_info,
1477 .get = aureon_ac97_mute_get,
1478 .put = aureon_ac97_mute_put,
1479 .private_value = AC97_MIC
1480 },
1481 {
1482 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1483 .name = "Mic Playback Volume",
1484 .info = aureon_ac97_vol_info,
1485 .get = aureon_ac97_vol_get,
1486 .put = aureon_ac97_vol_put,
1487 .private_value = AC97_MIC
1488 },
1489 {
1490 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1491 .name = "Mic Boost (+20dB)",
1492 .info = aureon_ac97_micboost_info,
1493 .get = aureon_ac97_micboost_get,
1494 .put = aureon_ac97_micboost_put
1495 }
1496};
1497
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001498static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 {
1500 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1501 .name = "AC97 Playback Switch",
1502 .info = aureon_ac97_mmute_info,
1503 .get = aureon_ac97_mmute_get,
1504 .put = aureon_ac97_mmute_put,
1505 .private_value = AC97_MASTER
1506 },
1507 {
1508 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1509 .name = "AC97 Playback Volume",
1510 .info = aureon_ac97_vol_info,
1511 .get = aureon_ac97_vol_get,
1512 .put = aureon_ac97_vol_put,
1513 .private_value = AC97_MASTER|AUREON_AC97_STEREO
1514 },
1515 {
1516 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1517 .name = "CD Playback Switch",
1518 .info = aureon_ac97_mute_info,
1519 .get = aureon_ac97_mute_get,
1520 .put = aureon_ac97_mute_put,
1521 .private_value = AC97_AUX
1522 },
1523 {
1524 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1525 .name = "CD Playback Volume",
1526 .info = aureon_ac97_vol_info,
1527 .get = aureon_ac97_vol_get,
1528 .put = aureon_ac97_vol_put,
1529 .private_value = AC97_AUX|AUREON_AC97_STEREO
1530 },
1531 {
1532 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1533 .name = "Phono Playback Switch",
1534 .info = aureon_ac97_mute_info,
1535 .get = aureon_ac97_mute_get,
1536 .put = aureon_ac97_mute_put,
1537 .private_value = AC97_CD,
1538 },
1539 {
1540 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1541 .name = "Phono Playback Volume",
1542 .info = aureon_ac97_vol_info,
1543 .get = aureon_ac97_vol_get,
1544 .put = aureon_ac97_vol_put,
1545 .private_value = AC97_CD|AUREON_AC97_STEREO
1546 },
1547 {
1548 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1549 .name = "Line Playback Switch",
1550 .info = aureon_ac97_mute_info,
1551 .get = aureon_ac97_mute_get,
1552 .put = aureon_ac97_mute_put,
1553 .private_value = AC97_LINE
1554 },
1555 {
1556 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1557 .name = "Line Playback Volume",
1558 .info = aureon_ac97_vol_info,
1559 .get = aureon_ac97_vol_get,
1560 .put = aureon_ac97_vol_put,
1561 .private_value = AC97_LINE|AUREON_AC97_STEREO
1562 },
1563 {
1564 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1565 .name = "Mic Playback Switch",
1566 .info = aureon_ac97_mute_info,
1567 .get = aureon_ac97_mute_get,
1568 .put = aureon_ac97_mute_put,
1569 .private_value = AC97_MIC
1570 },
1571 {
1572 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1573 .name = "Mic Playback Volume",
1574 .info = aureon_ac97_vol_info,
1575 .get = aureon_ac97_vol_get,
1576 .put = aureon_ac97_vol_put,
1577 .private_value = AC97_MIC
1578 },
1579 {
1580 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1581 .name = "Mic Boost (+20dB)",
1582 .info = aureon_ac97_micboost_info,
1583 .get = aureon_ac97_micboost_get,
1584 .put = aureon_ac97_micboost_put
1585 },
1586 {
1587 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1588 .name = "Aux Playback Switch",
1589 .info = aureon_ac97_mute_info,
1590 .get = aureon_ac97_mute_get,
1591 .put = aureon_ac97_mute_put,
1592 .private_value = AC97_VIDEO,
1593 },
1594 {
1595 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1596 .name = "Aux Playback Volume",
1597 .info = aureon_ac97_vol_info,
1598 .get = aureon_ac97_vol_get,
1599 .put = aureon_ac97_vol_put,
1600 .private_value = AC97_VIDEO|AUREON_AC97_STEREO
1601 }
1602};
1603
1604
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001605static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 {
1607 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1608 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
1609 .info = aureon_cs8415_mute_info,
1610 .get = aureon_cs8415_mute_get,
1611 .put = aureon_cs8415_mute_put
1612 },
1613 {
1614 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1615 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Source",
1616 .info = aureon_cs8415_mux_info,
1617 .get = aureon_cs8415_mux_get,
1618 .put = aureon_cs8415_mux_put,
1619 },
1620 {
1621 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1622 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ",CAPTURE,DEFAULT),
1623 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1624 .info = aureon_cs8415_qsub_info,
1625 .get = aureon_cs8415_qsub_get,
1626 },
1627 {
1628 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1629 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
1630 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1631 .info = aureon_cs8415_spdif_info,
1632 .get = aureon_cs8415_mask_get
1633 },
1634 {
1635 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1636 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
1637 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1638 .info = aureon_cs8415_spdif_info,
1639 .get = aureon_cs8415_spdif_get
1640 },
1641 {
1642 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1643 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Rate",
1644 .access =SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1645 .info = aureon_cs8415_rate_info,
1646 .get = aureon_cs8415_rate_get
1647 }
1648};
1649
1650
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001651static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652{
1653 unsigned int i, counts;
1654 int err;
1655
1656 counts = ARRAY_SIZE(aureon_dac_controls);
1657 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1658 counts -= 2; /* no side */
1659 for (i = 0; i < counts; i++) {
1660 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1661 if (err < 0)
1662 return err;
1663 }
1664
1665 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1666 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1667 if (err < 0)
1668 return err;
1669 }
1670
1671 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1672 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1673 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1674 if (err < 0)
1675 return err;
1676 }
1677 }
Takashi Iwai45fe7222006-01-13 13:50:16 +01001678 else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1680 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1681 if (err < 0)
1682 return err;
1683 }
1684 }
1685
Takashi Iwai45fe7222006-01-13 13:50:16 +01001686 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 unsigned char id;
1688 snd_ice1712_save_gpio_status(ice);
1689 id = aureon_cs8415_get(ice, CS8415_ID);
1690 if (id != 0x41)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001691 snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 else if ((id & 0x0F) != 0x01)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001693 snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 else {
1695 for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001696 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1698 if (err < 0)
1699 return err;
1700 if (i > 1)
1701 kctl->id.device = ice->pcm->device;
1702 }
1703 }
1704 snd_ice1712_restore_gpio_status(ice);
1705 }
1706
1707 return 0;
1708}
1709
1710
1711/*
1712 * initialize the chip
1713 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001714static int __devinit aureon_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
1716 static unsigned short wm_inits_aureon[] = {
1717 /* These come first to reduce init pop noise */
1718 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1719 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1720 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1721
1722 0x18, 0x000, /* All power-up */
1723
1724 0x16, 0x122, /* I2S, normal polarity, 24bit */
1725 0x17, 0x022, /* 256fs, slave mode */
1726 0x00, 0, /* DAC1 analog mute */
1727 0x01, 0, /* DAC2 analog mute */
1728 0x02, 0, /* DAC3 analog mute */
1729 0x03, 0, /* DAC4 analog mute */
1730 0x04, 0, /* DAC5 analog mute */
1731 0x05, 0, /* DAC6 analog mute */
1732 0x06, 0, /* DAC7 analog mute */
1733 0x07, 0, /* DAC8 analog mute */
1734 0x08, 0x100, /* master analog mute */
1735 0x09, 0xff, /* DAC1 digital full */
1736 0x0a, 0xff, /* DAC2 digital full */
1737 0x0b, 0xff, /* DAC3 digital full */
1738 0x0c, 0xff, /* DAC4 digital full */
1739 0x0d, 0xff, /* DAC5 digital full */
1740 0x0e, 0xff, /* DAC6 digital full */
1741 0x0f, 0xff, /* DAC7 digital full */
1742 0x10, 0xff, /* DAC8 digital full */
1743 0x11, 0x1ff, /* master digital full */
1744 0x12, 0x000, /* phase normal */
1745 0x13, 0x090, /* unmute DAC L/R */
1746 0x14, 0x000, /* all unmute */
1747 0x15, 0x000, /* no deemphasis, no ZFLG */
1748 0x19, 0x000, /* -12dB ADC/L */
1749 0x1a, 0x000, /* -12dB ADC/R */
1750 (unsigned short)-1
1751 };
1752 static unsigned short wm_inits_prodigy[] = {
1753
1754 /* These come first to reduce init pop noise */
1755 0x1b, 0x000, /* ADC Mux */
1756 0x1c, 0x009, /* Out Mux1 */
1757 0x1d, 0x009, /* Out Mux2 */
1758
1759 0x18, 0x000, /* All power-up */
1760
1761 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
1762 0x17, 0x006, /* 128fs, slave mode */
1763
1764 0x00, 0, /* DAC1 analog mute */
1765 0x01, 0, /* DAC2 analog mute */
1766 0x02, 0, /* DAC3 analog mute */
1767 0x03, 0, /* DAC4 analog mute */
1768 0x04, 0, /* DAC5 analog mute */
1769 0x05, 0, /* DAC6 analog mute */
1770 0x06, 0, /* DAC7 analog mute */
1771 0x07, 0, /* DAC8 analog mute */
1772 0x08, 0x100, /* master analog mute */
1773
1774 0x09, 0x7f, /* DAC1 digital full */
1775 0x0a, 0x7f, /* DAC2 digital full */
1776 0x0b, 0x7f, /* DAC3 digital full */
1777 0x0c, 0x7f, /* DAC4 digital full */
1778 0x0d, 0x7f, /* DAC5 digital full */
1779 0x0e, 0x7f, /* DAC6 digital full */
1780 0x0f, 0x7f, /* DAC7 digital full */
1781 0x10, 0x7f, /* DAC8 digital full */
1782 0x11, 0x1FF, /* master digital full */
1783
1784 0x12, 0x000, /* phase normal */
1785 0x13, 0x090, /* unmute DAC L/R */
1786 0x14, 0x000, /* all unmute */
1787 0x15, 0x000, /* no deemphasis, no ZFLG */
1788
1789 0x19, 0x000, /* -12dB ADC/L */
1790 0x1a, 0x000, /* -12dB ADC/R */
1791 (unsigned short)-1
1792
1793 };
1794 static unsigned short cs_inits[] = {
1795 0x0441, /* RUN */
1796 0x0180, /* no mute, OMCK output on RMCK pin */
1797 0x0201, /* S/PDIF source on RXP1 */
1798 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
1799 (unsigned short)-1
1800 };
1801 unsigned int tmp;
1802 unsigned short *p;
1803 int err, i;
1804
1805 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
1806 ice->num_total_dacs = 6;
1807 ice->num_total_adcs = 2;
1808 } else {
1809 /* aureon 7.1 and prodigy 7.1 */
1810 ice->num_total_dacs = 8;
1811 ice->num_total_adcs = 2;
1812 }
1813
1814 /* to remeber the register values of CS8415 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001815 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 if (! ice->akm)
1817 return -ENOMEM;
1818 ice->akm_codecs = 1;
1819
1820 if ((err = aureon_ac97_init(ice)) != 0)
1821 return err;
1822
1823 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
1824
1825 /* reset the wm codec as the SPI mode */
1826 snd_ice1712_save_gpio_status(ice);
1827 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
1828
1829 tmp = snd_ice1712_gpio_read(ice);
1830 tmp &= ~AUREON_WM_RESET;
1831 snd_ice1712_gpio_write(ice, tmp);
1832 udelay(1);
1833 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
1834 snd_ice1712_gpio_write(ice, tmp);
1835 udelay(1);
1836 tmp |= AUREON_WM_RESET;
1837 snd_ice1712_gpio_write(ice, tmp);
1838 udelay(1);
1839
1840 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01001841 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
1842 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 p = wm_inits_prodigy;
1844 else
1845 p = wm_inits_aureon;
1846 for (; *p != (unsigned short)-1; p += 2)
1847 wm_put(ice, p[0], p[1]);
1848
1849 /* initialize CS8415A codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01001850 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
1851 for (p = cs_inits; *p != (unsigned short)-1; p++)
1852 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
1853 ice->spec.aureon.cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
Takashi Iwai45fe7222006-01-13 13:50:16 +01001855 aureon_set_headphone_amp(ice, 1);
1856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
1858 snd_ice1712_restore_gpio_status(ice);
1859
1860 ice->spec.aureon.master[0] = WM_VOL_MUTE;
1861 ice->spec.aureon.master[1] = WM_VOL_MUTE;
1862 for (i = 0; i < ice->num_total_dacs; i++) {
1863 ice->spec.aureon.vol[i] = WM_VOL_MUTE;
1864 wm_set_vol(ice, i, ice->spec.aureon.vol[i], ice->spec.aureon.master[i % 2]);
1865 }
1866
1867 return 0;
1868}
1869
1870
1871/*
1872 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
1873 * hence the driver needs to sets up it properly.
1874 */
1875
1876static unsigned char aureon51_eeprom[] __devinitdata = {
1877 0x0a, /* SYSCONF: clock 512, spdif-in/ADC, 3DACs */
1878 0x80, /* ACLINK: I2S */
1879 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1880 0xc3, /* SPDIF: out-en, out-int, spdif-in */
1881 0xff, /* GPIO_DIR */
1882 0xff, /* GPIO_DIR1 */
1883 0x5f, /* GPIO_DIR2 */
1884 0x00, /* GPIO_MASK */
1885 0x00, /* GPIO_MASK1 */
1886 0x00, /* GPIO_MASK2 */
1887 0x00, /* GPIO_STATE */
1888 0x00, /* GPIO_STATE1 */
1889 0x00, /* GPIO_STATE2 */
1890};
1891
1892static unsigned char aureon71_eeprom[] __devinitdata = {
1893 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
1894 0x80, /* ACLINK: I2S */
1895 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1896 0xc3, /* SPDIF: out-en, out-int, spdif-in */
1897 0xff, /* GPIO_DIR */
1898 0xff, /* GPIO_DIR1 */
1899 0x5f, /* GPIO_DIR2 */
1900 0x00, /* GPIO_MASK */
1901 0x00, /* GPIO_MASK1 */
1902 0x00, /* GPIO_MASK2 */
1903 0x00, /* GPIO_STATE */
1904 0x00, /* GPIO_STATE1 */
1905 0x00, /* GPIO_STATE2 */
1906};
1907
1908static unsigned char prodigy71_eeprom[] __devinitdata = {
1909 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
1910 0x80, /* ACLINK: I2S */
1911 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1912 0xc3, /* SPDIF: out-en, out-int, spdif-in */
1913 0xff, /* GPIO_DIR */
1914 0xff, /* GPIO_DIR1 */
1915 0x5f, /* GPIO_DIR2 */
1916 0x00, /* GPIO_MASK */
1917 0x00, /* GPIO_MASK1 */
1918 0x00, /* GPIO_MASK2 */
1919 0x00, /* GPIO_STATE */
1920 0x00, /* GPIO_STATE1 */
1921 0x00, /* GPIO_STATE2 */
1922};
1923
Takashi Iwai45fe7222006-01-13 13:50:16 +01001924static unsigned char prodigy71lt_eeprom[] __devinitdata = {
1925 0x0b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
1926 0x80, /* ACLINK: I2S */
1927 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1928 0xc3, /* SPDUF: out-en, out-int */
1929 0x00, /* GPIO_DIR */
1930 0x07, /* GPIO_DIR1 */
1931 0x00, /* GPIO_DIR2 */
1932 0xff, /* GPIO_MASK */
1933 0xf8, /* GPIO_MASK1 */
1934 0xff, /* GPIO_MASK2 */
1935 0x00, /* GPIO_STATE */
1936 0x00, /* GPIO_STATE1 */
1937 0x00, /* GPIO_STATE2 */
1938};
1939
1940
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941/* entry point */
1942struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
1943 {
1944 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
1945 .name = "Terratec Aureon 5.1-Sky",
1946 .model = "aureon51",
1947 .chip_init = aureon_init,
1948 .build_controls = aureon_add_controls,
1949 .eeprom_size = sizeof(aureon51_eeprom),
1950 .eeprom_data = aureon51_eeprom,
1951 .driver = "Aureon51",
1952 },
1953 {
1954 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
1955 .name = "Terratec Aureon 7.1-Space",
1956 .model = "aureon71",
1957 .chip_init = aureon_init,
1958 .build_controls = aureon_add_controls,
1959 .eeprom_size = sizeof(aureon71_eeprom),
1960 .eeprom_data = aureon71_eeprom,
1961 .driver = "Aureon71",
1962 },
1963 {
1964 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
1965 .name = "Terratec Aureon 7.1-Universe",
1966 .model = "universe",
1967 .chip_init = aureon_init,
1968 .build_controls = aureon_add_controls,
1969 .eeprom_size = sizeof(aureon71_eeprom),
1970 .eeprom_data = aureon71_eeprom,
1971 .driver = "Aureon71Universe",
1972 },
1973 {
1974 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
1975 .name = "Audiotrak Prodigy 7.1",
1976 .model = "prodigy71",
1977 .chip_init = aureon_init,
1978 .build_controls = aureon_add_controls,
1979 .eeprom_size = sizeof(prodigy71_eeprom),
1980 .eeprom_data = prodigy71_eeprom,
1981 .driver = "Prodigy71", /* should be identical with Aureon71 */
1982 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01001983 {
1984 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
1985 .name = "Audiotrak Prodigy 7.1 LT",
1986 .model = "prodigy71lt",
1987 .chip_init = aureon_init,
1988 .build_controls = aureon_add_controls,
1989 .eeprom_size = sizeof(prodigy71lt_eeprom),
1990 .eeprom_data = prodigy71lt_eeprom,
1991 .driver = "Prodigy71LT",
1992 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 { } /* terminator */
1994};