blob: 3b3cf4ac9060ac41b9876e52c94a4151e61cdce5 [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.
Alexander Beregalov1ce211a2008-09-07 01:19:00 +040047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/delay.h>
50#include <linux/interrupt.h>
51#include <linux/init.h>
52#include <linux/slab.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010053#include <linux/mutex.h>
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <sound/core.h>
56
57#include "ice1712.h"
58#include "envy24ht.h"
59#include "aureon.h"
Takashi Iwaif640c322006-08-30 16:57:37 +020060#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010062/* AC97 register cache for Aureon */
63struct aureon_spec {
64 unsigned short stac9744[64];
65 unsigned int cs8415_mux;
66 unsigned short master[2];
67 unsigned short vol[8];
68 unsigned char pca9554_out;
69};
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071/* WM8770 registers */
72#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
73#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
74#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
75#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
76#define WM_PHASE_SWAP 0x12 /* DAC phase */
77#define WM_DAC_CTRL1 0x13 /* DAC control bits */
78#define WM_MUTE 0x14 /* mute controls */
79#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
80#define WM_INT_CTRL 0x16 /* interface control */
81#define WM_MASTER 0x17 /* master clock and mode */
82#define WM_POWERDOWN 0x18 /* power-down controls */
83#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
84#define WM_ADC_MUX 0x1b /* input MUX */
85#define WM_OUT_MUX1 0x1c /* output MUX */
86#define WM_OUT_MUX2 0x1e /* output MUX */
87#define WM_RESET 0x1f /* software reset */
88
89/* CS8415A registers */
90#define CS8415_CTRL1 0x01
91#define CS8415_CTRL2 0x02
92#define CS8415_QSUB 0x14
93#define CS8415_RATIO 0x1E
94#define CS8415_C_BUFFER 0x20
95#define CS8415_ID 0x7F
96
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +020097/* PCA9554 registers */
98#define PCA9554_DEV 0x40 /* I2C device address */
99#define PCA9554_IN 0x00 /* input port */
100#define PCA9554_OUT 0x01 /* output port */
101#define PCA9554_INVERT 0x02 /* input invert */
102#define PCA9554_DIR 0x03 /* port directions */
103
104/*
105 * Aureon Universe additional controls using PCA9554
106 */
107
108/*
109 * Send data to pca9554
110 */
111static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg,
112 unsigned char data)
113{
114 unsigned int tmp;
115 int i, j;
116 unsigned char dev = PCA9554_DEV; /* ID 0100000, write */
117 unsigned char val = 0;
118
119 tmp = snd_ice1712_gpio_read(ice);
120
121 snd_ice1712_gpio_set_mask(ice, ~(AUREON_SPI_MOSI|AUREON_SPI_CLK|
122 AUREON_WM_RW|AUREON_WM_CS|
123 AUREON_CS8415_CS));
124 tmp |= AUREON_WM_RW;
125 tmp |= AUREON_CS8415_CS | AUREON_WM_CS; /* disable SPI devices */
126
127 tmp &= ~AUREON_SPI_MOSI;
128 tmp &= ~AUREON_SPI_CLK;
129 snd_ice1712_gpio_write(ice, tmp);
130 udelay(50);
131
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400132 /*
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200133 * send i2c stop condition and start condition
134 * to obtain sane state
135 */
136 tmp |= AUREON_SPI_CLK;
137 snd_ice1712_gpio_write(ice, tmp);
138 udelay(50);
139 tmp |= AUREON_SPI_MOSI;
140 snd_ice1712_gpio_write(ice, tmp);
141 udelay(100);
142 tmp &= ~AUREON_SPI_MOSI;
143 snd_ice1712_gpio_write(ice, tmp);
144 udelay(50);
145 tmp &= ~AUREON_SPI_CLK;
146 snd_ice1712_gpio_write(ice, tmp);
147 udelay(100);
148 /*
149 * send device address, command and value,
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300150 * skipping ack cycles in between
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200151 */
152 for (j = 0; j < 3; j++) {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400153 switch (j) {
154 case 0:
155 val = dev;
156 break;
157 case 1:
158 val = reg;
159 break;
160 case 2:
161 val = data;
162 break;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200163 }
164 for (i = 7; i >= 0; i--) {
165 tmp &= ~AUREON_SPI_CLK;
166 snd_ice1712_gpio_write(ice, tmp);
167 udelay(40);
168 if (val & (1 << i))
169 tmp |= AUREON_SPI_MOSI;
170 else
171 tmp &= ~AUREON_SPI_MOSI;
172 snd_ice1712_gpio_write(ice, tmp);
173 udelay(40);
174 tmp |= AUREON_SPI_CLK;
175 snd_ice1712_gpio_write(ice, tmp);
176 udelay(40);
177 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400178 tmp &= ~AUREON_SPI_CLK;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200179 snd_ice1712_gpio_write(ice, tmp);
180 udelay(40);
181 tmp |= AUREON_SPI_CLK;
182 snd_ice1712_gpio_write(ice, tmp);
183 udelay(40);
184 tmp &= ~AUREON_SPI_CLK;
185 snd_ice1712_gpio_write(ice, tmp);
186 udelay(40);
187 }
188 tmp &= ~AUREON_SPI_CLK;
189 snd_ice1712_gpio_write(ice, tmp);
190 udelay(40);
191 tmp &= ~AUREON_SPI_MOSI;
192 snd_ice1712_gpio_write(ice, tmp);
193 udelay(40);
194 tmp |= AUREON_SPI_CLK;
195 snd_ice1712_gpio_write(ice, tmp);
196 udelay(50);
197 tmp |= AUREON_SPI_MOSI;
198 snd_ice1712_gpio_write(ice, tmp);
199 udelay(100);
200}
201
202static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol,
203 struct snd_ctl_elem_info *uinfo)
204{
Takashi Iwaia2af0502012-10-17 09:21:48 +0200205 static const char * const texts[3] =
206 {"Internal Aux", "Wavetable", "Rear Line-In"};
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200207
208 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
209 uinfo->count = 1;
210 uinfo->value.enumerated.items = 3;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400211 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200212 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
213 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
214 return 0;
215}
216
217static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
218 struct snd_ctl_elem_value *ucontrol)
219{
220 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100221 struct aureon_spec *spec = ice->spec;
222 ucontrol->value.enumerated.item[0] = spec->pca9554_out;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200223 return 0;
224}
225
226static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
227 struct snd_ctl_elem_value *ucontrol)
228{
229 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100230 struct aureon_spec *spec = ice->spec;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200231 unsigned char oval, nval;
232 int change;
233
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100234 nval = ucontrol->value.enumerated.item[0];
235 if (nval >= 3)
236 return -EINVAL;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200237 snd_ice1712_save_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100238 oval = spec->pca9554_out;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400239 change = (oval != nval);
240 if (change) {
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200241 aureon_pca9554_write(ice, PCA9554_OUT, nval);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100242 spec->pca9554_out = nval;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200243 }
244 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200245 return change;
246}
247
248
249static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
250 unsigned short val)
251{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100252 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 unsigned int tmp;
254
255 /* Send address to XILINX chip */
256 tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F);
257 snd_ice1712_gpio_write(ice, tmp);
258 udelay(10);
259 tmp |= AUREON_AC97_ADDR;
260 snd_ice1712_gpio_write(ice, tmp);
261 udelay(10);
262 tmp &= ~AUREON_AC97_ADDR;
263 snd_ice1712_gpio_write(ice, tmp);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400264 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
266 /* Send low-order byte to XILINX chip */
267 tmp &= ~AUREON_AC97_DATA_MASK;
268 tmp |= val & AUREON_AC97_DATA_MASK;
269 snd_ice1712_gpio_write(ice, tmp);
270 udelay(10);
271 tmp |= AUREON_AC97_DATA_LOW;
272 snd_ice1712_gpio_write(ice, tmp);
273 udelay(10);
274 tmp &= ~AUREON_AC97_DATA_LOW;
275 snd_ice1712_gpio_write(ice, tmp);
276 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 /* Send high-order byte to XILINX chip */
279 tmp &= ~AUREON_AC97_DATA_MASK;
280 tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
281
282 snd_ice1712_gpio_write(ice, tmp);
283 udelay(10);
284 tmp |= AUREON_AC97_DATA_HIGH;
285 snd_ice1712_gpio_write(ice, tmp);
286 udelay(10);
287 tmp &= ~AUREON_AC97_DATA_HIGH;
288 snd_ice1712_gpio_write(ice, tmp);
289 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 /* Instruct XILINX chip to parse the data to the STAC9744 chip */
292 tmp |= AUREON_AC97_COMMIT;
293 snd_ice1712_gpio_write(ice, tmp);
294 udelay(10);
295 tmp &= ~AUREON_AC97_COMMIT;
296 snd_ice1712_gpio_write(ice, tmp);
297 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 /* Store the data in out private buffer */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100300 spec->stac9744[(reg & 0x7F) >> 1] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100303static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100305 struct aureon_spec *spec = ice->spec;
306 return spec->stac9744[(reg & 0x7F) >> 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307}
308
309/*
310 * Initialize STAC9744 chip
311 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400312static int aureon_ac97_init(struct snd_ice1712 *ice)
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200313{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100314 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 int i;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100316 static const unsigned short ac97_defaults[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 0x00, 0x9640,
318 0x02, 0x8000,
319 0x04, 0x8000,
320 0x06, 0x8000,
321 0x0C, 0x8008,
322 0x0E, 0x8008,
323 0x10, 0x8808,
324 0x12, 0x8808,
325 0x14, 0x8808,
326 0x16, 0x8808,
327 0x18, 0x8808,
328 0x1C, 0x8000,
329 0x26, 0x000F,
330 0x28, 0x0201,
331 0x2C, 0xBB80,
332 0x32, 0xBB80,
333 0x7C, 0x8384,
334 0x7E, 0x7644,
335 (unsigned short)-1
336 };
337 unsigned int tmp;
338
339 /* Cold reset */
340 tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
341 snd_ice1712_gpio_write(ice, tmp);
342 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400343
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 tmp &= ~AUREON_AC97_RESET;
345 snd_ice1712_gpio_write(ice, tmp);
346 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 tmp |= AUREON_AC97_RESET;
349 snd_ice1712_gpio_write(ice, tmp);
350 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400351
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100352 memset(&spec->stac9744, 0, sizeof(spec->stac9744));
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400353 for (i = 0; ac97_defaults[i] != (unsigned short)-1; i += 2)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100354 spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400355
356 /* Unmute AC'97 master volume permanently - muting is done by WM8770 */
357 aureon_ac97_write(ice, AC97_MASTER, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 return 0;
360}
361
362#define AUREON_AC97_STEREO 0x80
363
364/*
365 * AC'97 volume controls
366 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100367static int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
370 uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1;
371 uinfo->value.integer.min = 0;
372 uinfo->value.integer.max = 31;
373 return 0;
374}
375
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100376static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100378 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 unsigned short vol;
380
Ingo Molnar62932df2006-01-16 16:34:20 +0100381 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
384 ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
385 if (kcontrol->private_value & AUREON_AC97_STEREO)
386 ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
387
Ingo Molnar62932df2006-01-16 16:34:20 +0100388 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 return 0;
390}
391
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100392static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100394 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 unsigned short ovol, nvol;
396 int change;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 snd_ice1712_save_gpio_status(ice);
399
400 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
401 nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F;
402 if (kcontrol->private_value & AUREON_AC97_STEREO)
403 nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
404 nvol |= ovol & ~0x1F1F;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400405
406 change = (ovol != nvol);
407 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
409
410 snd_ice1712_restore_gpio_status(ice);
411
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400412 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
415/*
416 * AC'97 mute controls
417 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200418#define aureon_ac97_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100420static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100422 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Ingo Molnar62932df2006-01-16 16:34:20 +0100424 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400426 ucontrol->value.integer.value[0] = aureon_ac97_read(ice,
427 kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Ingo Molnar62932df2006-01-16 16:34:20 +0100429 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 return 0;
431}
432
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100433static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100435 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 unsigned short ovol, nvol;
437 int change;
438
439 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400442 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~0x8000);
443
444 change = (ovol != nvol);
445 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 snd_ice1712_restore_gpio_status(ice);
449
450 return change;
451}
452
453/*
454 * AC'97 mute controls
455 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200456#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100458static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100460 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Ingo Molnar62932df2006-01-16 16:34:20 +0100462 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
465
Ingo Molnar62932df2006-01-16 16:34:20 +0100466 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 return 0;
468}
469
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100470static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100472 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 unsigned short ovol, nvol;
474 int change;
475
476 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 ovol = aureon_ac97_read(ice, AC97_MIC);
479 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400480
481 change = (ovol != nvol);
482 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 aureon_ac97_write(ice, AC97_MIC, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 snd_ice1712_restore_gpio_status(ice);
486
487 return change;
488}
489
490/*
491 * write data in the SPI mode
492 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100493static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
495 unsigned int tmp;
496 int i;
Takashi Iwai45fe7222006-01-13 13:50:16 +0100497 unsigned int mosi, clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 tmp = snd_ice1712_gpio_read(ice);
500
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100501 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
502 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100503 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
504 mosi = PRODIGY_SPI_MOSI;
505 clk = PRODIGY_SPI_CLK;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400506 } else {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100507 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
508 AUREON_WM_CS|AUREON_CS8415_CS));
509 mosi = AUREON_SPI_MOSI;
510 clk = AUREON_SPI_CLK;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400511
Takashi Iwai45fe7222006-01-13 13:50:16 +0100512 tmp |= AUREON_WM_RW;
513 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 tmp &= ~cs;
516 snd_ice1712_gpio_write(ice, tmp);
517 udelay(1);
518
519 for (i = bits - 1; i >= 0; i--) {
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 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100524 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100526 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 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
Takashi Iwai45fe7222006-01-13 13:50:16 +0100534 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 tmp |= cs;
536 snd_ice1712_gpio_write(ice, tmp);
537 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100538 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 snd_ice1712_gpio_write(ice, tmp);
540 udelay(1);
541}
542
543/*
544 * Read data in SPI mode
545 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400546static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs,
547 unsigned int data, int bits, unsigned char *buffer, int size)
548{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 int i, j;
550 unsigned int tmp;
551
552 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
553 snd_ice1712_gpio_write(ice, tmp);
554 tmp &= ~cs;
555 snd_ice1712_gpio_write(ice, tmp);
556 udelay(1);
557
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400558 for (i = bits-1; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if (data & (1 << i))
560 tmp |= AUREON_SPI_MOSI;
561 else
562 tmp &= ~AUREON_SPI_MOSI;
563 snd_ice1712_gpio_write(ice, tmp);
564 udelay(1);
565
566 tmp |= AUREON_SPI_CLK;
567 snd_ice1712_gpio_write(ice, tmp);
568 udelay(1);
569
570 tmp &= ~AUREON_SPI_CLK;
571 snd_ice1712_gpio_write(ice, tmp);
572 udelay(1);
573 }
574
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400575 for (j = 0; j < size; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 unsigned char outdata = 0;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400577 for (i = 7; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 tmp = snd_ice1712_gpio_read(ice);
579 outdata <<= 1;
580 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
581 udelay(1);
582
583 tmp |= AUREON_SPI_CLK;
584 snd_ice1712_gpio_write(ice, tmp);
585 udelay(1);
586
587 tmp &= ~AUREON_SPI_CLK;
588 snd_ice1712_gpio_write(ice, tmp);
589 udelay(1);
590 }
591 buffer[j] = outdata;
592 }
593
594 tmp |= cs;
595 snd_ice1712_gpio_write(ice, tmp);
596}
597
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400598static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg)
599{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 unsigned char val;
601 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
602 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
603 return val;
604}
605
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400606static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg,
607 unsigned char *buffer, int size)
608{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
610 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
611}
612
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400613static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg,
614 unsigned char val)
615{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
617}
618
619/*
620 * get the current register value of WM codec
621 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100622static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
624 reg <<= 1;
625 return ((unsigned short)ice->akm[0].images[reg] << 8) |
626 ice->akm[0].images[reg + 1];
627}
628
629/*
630 * set the register value of WM codec
631 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100632static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100634 aureon_spi_write(ice,
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100635 ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
636 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
637 PRODIGY_WM_CS : AUREON_WM_CS),
Takashi Iwai45fe7222006-01-13 13:50:16 +0100638 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639}
640
641/*
642 * set the register value of WM codec and remember it
643 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100644static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
646 wm_put_nocache(ice, reg, val);
647 reg <<= 1;
648 ice->akm[0].images[reg] = val >> 8;
649 ice->akm[0].images[reg + 1] = val;
650}
651
652/*
653 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200654#define aureon_mono_bool_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656/*
657 * AC'97 master playback mute controls (Mute on WM8770 chip)
658 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200659#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100661static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100663 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
Ingo Molnar62932df2006-01-16 16:34:20 +0100665 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
668
Ingo Molnar62932df2006-01-16 16:34:20 +0100669 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 return 0;
671}
672
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400673static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
674{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100675 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 unsigned short ovol, nvol;
677 int change;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 ovol = wm_get(ice, WM_OUT_MUX1);
682 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400683 change = (ovol != nvol);
684 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 wm_put(ice, WM_OUT_MUX1, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 snd_ice1712_restore_gpio_status(ice);
688
689 return change;
690}
691
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100692static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -10000, 100, 1);
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100693static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
694static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
695static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
696static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
Takashi Iwaif640c322006-08-30 16:57:37 +0200697
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100698#define WM_VOL_MAX 100
699#define WM_VOL_CNT 101 /* 0dB .. -100dB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700#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;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400705
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100706 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 nvol = 0;
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100708 } else {
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100709 nvol = ((vol % WM_VOL_CNT) * (master % WM_VOL_CNT)) /
710 WM_VOL_MAX;
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100711 nvol += 0x1b;
712 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 wm_put(ice, index, nvol);
715 wm_put_nocache(ice, index, 0x180 | nvol);
716}
717
718/*
719 * DAC mute control
720 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200721#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100723static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100725 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Ingo Molnar62932df2006-01-16 16:34:20 +0100727 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100729 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 return 0;
731}
732
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100733static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100735 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 unsigned short nval, oval;
737 int change;
738
739 snd_ice1712_save_gpio_status(ice);
740 oval = wm_get(ice, WM_MUTE);
741 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400742 change = (oval != nval);
743 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 wm_put(ice, WM_MUTE, nval);
745 snd_ice1712_restore_gpio_status(ice);
746
747 return change;
748}
749
750/*
751 * Master volume attenuation mixer control
752 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100753static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754{
755 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
756 uinfo->count = 2;
757 uinfo->value.integer.min = 0;
758 uinfo->value.integer.max = WM_VOL_MAX;
759 return 0;
760}
761
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100762static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100764 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100765 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 int i;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400767 for (i = 0; i < 2; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100768 ucontrol->value.integer.value[i] =
769 spec->master[i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return 0;
771}
772
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100773static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100775 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100776 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 int ch, change = 0;
778
779 snd_ice1712_save_gpio_status(ice);
780 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100781 unsigned int vol = ucontrol->value.integer.value[ch];
782 if (vol > WM_VOL_MAX)
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100783 vol = WM_VOL_MAX;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100784 vol |= spec->master[ch] & WM_VOL_MUTE;
785 if (vol != spec->master[ch]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100787 spec->master[ch] = vol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
789 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100790 spec->vol[dac + ch],
791 spec->master[ch]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 change = 1;
793 }
794 }
795 snd_ice1712_restore_gpio_status(ice);
796 return change;
797}
798
799/*
800 * DAC volume attenuation mixer control
801 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100802static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
804 int voices = kcontrol->private_value >> 8;
805 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
806 uinfo->count = voices;
807 uinfo->value.integer.min = 0; /* mute (-101dB) */
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100808 uinfo->value.integer.max = WM_VOL_MAX; /* 0dB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 return 0;
810}
811
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100812static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100814 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100815 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 int i, ofs, voices;
817
818 voices = kcontrol->private_value >> 8;
819 ofs = kcontrol->private_value & 0xff;
820 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100821 ucontrol->value.integer.value[i] =
822 spec->vol[ofs+i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 return 0;
824}
825
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100826static int wm_vol_put(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);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100829 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 int i, idx, ofs, voices;
831 int change = 0;
832
833 voices = kcontrol->private_value >> 8;
834 ofs = kcontrol->private_value & 0xff;
835 snd_ice1712_save_gpio_status(ice);
836 for (i = 0; i < voices; i++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100837 unsigned int vol = ucontrol->value.integer.value[i];
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100838 if (vol > WM_VOL_MAX)
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100839 vol = WM_VOL_MAX;
840 vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100841 if (vol != spec->vol[ofs+i]) {
842 spec->vol[ofs+i] = vol;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100843 idx = WM_DAC_ATTEN + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100844 wm_set_vol(ice, idx, spec->vol[ofs + i],
845 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 change = 1;
847 }
848 }
849 snd_ice1712_restore_gpio_status(ice);
850 return change;
851}
852
853/*
854 * WM8770 mute control
855 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400856static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
857{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
859 uinfo->count = kcontrol->private_value >> 8;
860 uinfo->value.integer.min = 0;
861 uinfo->value.integer.max = 1;
862 return 0;
863}
864
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100865static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100867 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100868 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 int voices, ofs, i;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 voices = kcontrol->private_value >> 8;
872 ofs = kcontrol->private_value & 0xFF;
873
874 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100875 ucontrol->value.integer.value[i] =
876 (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 return 0;
878}
879
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100880static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100882 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100883 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 int change = 0, voices, ofs, i;
885
886 voices = kcontrol->private_value >> 8;
887 ofs = kcontrol->private_value & 0xFF;
888
889 snd_ice1712_save_gpio_status(ice);
890 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100891 int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 if (ucontrol->value.integer.value[i] != val) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100893 spec->vol[ofs + i] &= ~WM_VOL_MUTE;
894 spec->vol[ofs + i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100896 wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
897 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 change = 1;
899 }
900 }
901 snd_ice1712_restore_gpio_status(ice);
902
903 return change;
904}
905
906/*
907 * WM8770 master mute control
908 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200909#define wm_master_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100911static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100913 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100914 struct aureon_spec *spec = ice->spec;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400915
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100916 ucontrol->value.integer.value[0] =
917 (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
918 ucontrol->value.integer.value[1] =
919 (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 return 0;
921}
922
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100923static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100925 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100926 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 int change = 0, i;
928
929 snd_ice1712_save_gpio_status(ice);
930 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100931 int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 if (ucontrol->value.integer.value[i] != val) {
933 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100934 spec->master[i] &= ~WM_VOL_MUTE;
935 spec->master[i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
937 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
938 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100939 spec->vol[dac + i],
940 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 change = 1;
942 }
943 }
944 snd_ice1712_restore_gpio_status(ice);
945
946 return change;
947}
948
949/* digital master volume */
950#define PCM_0dB 0xff
951#define PCM_RES 128 /* -64dB */
952#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100953static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954{
955 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
956 uinfo->count = 1;
957 uinfo->value.integer.min = 0; /* mute (-64dB) */
958 uinfo->value.integer.max = PCM_RES; /* 0dB */
959 return 0;
960}
961
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100962static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100964 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 unsigned short val;
966
Ingo Molnar62932df2006-01-16 16:34:20 +0100967 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
969 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
970 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100971 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 return 0;
973}
974
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100975static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100977 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 unsigned short ovol, nvol;
979 int change = 0;
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100982 if (nvol > PCM_RES)
983 return -EINVAL;
984 snd_ice1712_save_gpio_status(ice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
986 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
987 if (ovol != nvol) {
988 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
989 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
990 change = 1;
991 }
992 snd_ice1712_restore_gpio_status(ice);
993 return change;
994}
995
996/*
997 * ADC mute control
998 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200999#define wm_adc_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001001static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001003 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 unsigned short val;
1005 int i;
1006
Ingo Molnar62932df2006-01-16 16:34:20 +01001007 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 for (i = 0; i < 2; i++) {
1009 val = wm_get(ice, WM_ADC_GAIN + i);
1010 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
1011 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001012 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 return 0;
1014}
1015
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001016static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001018 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 unsigned short new, old;
1020 int i, change = 0;
1021
1022 snd_ice1712_save_gpio_status(ice);
1023 for (i = 0; i < 2; i++) {
1024 old = wm_get(ice, WM_ADC_GAIN + i);
1025 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
1026 if (new != old) {
1027 wm_put(ice, WM_ADC_GAIN + i, new);
1028 change = 1;
1029 }
1030 }
1031 snd_ice1712_restore_gpio_status(ice);
1032
1033 return change;
1034}
1035
1036/*
1037 * ADC gain mixer control
1038 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001039static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040{
1041 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1042 uinfo->count = 2;
1043 uinfo->value.integer.min = 0; /* -12dB */
1044 uinfo->value.integer.max = 0x1f; /* 19dB */
1045 return 0;
1046}
1047
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001048static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001050 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 int i, idx;
1052 unsigned short vol;
1053
Ingo Molnar62932df2006-01-16 16:34:20 +01001054 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 for (i = 0; i < 2; i++) {
1056 idx = WM_ADC_GAIN + i;
1057 vol = wm_get(ice, idx) & 0x1f;
1058 ucontrol->value.integer.value[i] = vol;
1059 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001060 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 return 0;
1062}
1063
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001064static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001066 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 int i, idx;
1068 unsigned short ovol, nvol;
1069 int change = 0;
1070
1071 snd_ice1712_save_gpio_status(ice);
1072 for (i = 0; i < 2; i++) {
1073 idx = WM_ADC_GAIN + i;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +01001074 nvol = ucontrol->value.integer.value[i] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 ovol = wm_get(ice, idx);
1076 if ((ovol & 0x1f) != nvol) {
1077 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1078 change = 1;
1079 }
1080 }
1081 snd_ice1712_restore_gpio_status(ice);
1082 return change;
1083}
1084
1085/*
1086 * ADC input mux mixer control
1087 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001088static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001090 static const char * const texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001091 "CD", /* AIN1 */
1092 "Aux", /* AIN2 */
1093 "Line", /* AIN3 */
1094 "Mic", /* AIN4 */
1095 "AC97" /* AIN5 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001097 static const char * const universe_texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001098 "Aux1", /* AIN1 */
1099 "CD", /* AIN2 */
1100 "Phono", /* AIN3 */
1101 "Line", /* AIN4 */
1102 "Aux2", /* AIN5 */
1103 "Mic", /* AIN6 */
1104 "Aux3", /* AIN7 */
1105 "AC97" /* AIN8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001107 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
1109 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1110 uinfo->count = 2;
1111 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1112 uinfo->value.enumerated.items = 8;
1113 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1114 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1115 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001116 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 uinfo->value.enumerated.items = 5;
1118 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1119 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1120 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1121 }
1122 return 0;
1123}
1124
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001125static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001127 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 unsigned short val;
1129
Ingo Molnar62932df2006-01-16 16:34:20 +01001130 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001132 ucontrol->value.enumerated.item[0] = val & 7;
1133 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001134 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 return 0;
1136}
1137
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001138static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001140 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 unsigned short oval, nval;
1142 int change;
1143
1144 snd_ice1712_save_gpio_status(ice);
1145 oval = wm_get(ice, WM_ADC_MUX);
1146 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001147 nval |= ucontrol->value.enumerated.item[0] & 7;
1148 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 change = (oval != nval);
1150 if (change)
1151 wm_put(ice, WM_ADC_MUX, nval);
1152 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001153 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154}
1155
1156/*
1157 * CS8415 Input mux
1158 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001159static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001161 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai32b47da2007-01-29 15:26:36 +01001162 static const char * const aureon_texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001163 "CD", /* RXP0 */
1164 "Optical" /* RXP1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001166 static const char * const prodigy_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 "CD",
1168 "Coax"
1169 };
1170 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1171 uinfo->count = 1;
1172 uinfo->value.enumerated.items = 2;
1173 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1174 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1175 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1176 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1177 else
1178 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1179 return 0;
1180}
1181
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001182static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001184 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001185 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001187 /* snd_ice1712_save_gpio_status(ice); */
1188 /* val = aureon_cs8415_get(ice, CS8415_CTRL2); */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001189 ucontrol->value.enumerated.item[0] = spec->cs8415_mux;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001190 /* snd_ice1712_restore_gpio_status(ice); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 return 0;
1192}
1193
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001194static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001196 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001197 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 unsigned short oval, nval;
1199 int change;
1200
1201 snd_ice1712_save_gpio_status(ice);
1202 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1203 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001204 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 change = (oval != nval);
1206 if (change)
1207 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1208 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001209 spec->cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 return change;
1211}
1212
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001213static int aureon_cs8415_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
1215 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1216 uinfo->count = 1;
1217 uinfo->value.integer.min = 0;
1218 uinfo->value.integer.max = 192000;
1219 return 0;
1220}
1221
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001222static int aureon_cs8415_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001224 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 unsigned char ratio;
1226 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1227 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1228 return 0;
1229}
1230
1231/*
1232 * CS8415A Mute
1233 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001234#define aureon_cs8415_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001236static int aureon_cs8415_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001238 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 snd_ice1712_save_gpio_status(ice);
1240 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1241 snd_ice1712_restore_gpio_status(ice);
1242 return 0;
1243}
1244
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001245static int aureon_cs8415_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001247 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 unsigned char oval, nval;
1249 int change;
1250 snd_ice1712_save_gpio_status(ice);
1251 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1252 if (ucontrol->value.integer.value[0])
1253 nval = oval & ~0x20;
1254 else
1255 nval = oval | 0x20;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001256 change = (oval != nval);
1257 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1259 snd_ice1712_restore_gpio_status(ice);
1260 return change;
1261}
1262
1263/*
1264 * CS8415A Q-Sub info
1265 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001266static int aureon_cs8415_qsub_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1267{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1269 uinfo->count = 10;
1270 return 0;
1271}
1272
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001273static int aureon_cs8415_qsub_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1274{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001275 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001276
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 snd_ice1712_save_gpio_status(ice);
1278 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1279 snd_ice1712_restore_gpio_status(ice);
1280
1281 return 0;
1282}
1283
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001284static int aureon_cs8415_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1285{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1287 uinfo->count = 1;
1288 return 0;
1289}
1290
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001291static int aureon_cs8415_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1292{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 memset(ucontrol->value.iec958.status, 0xFF, 24);
1294 return 0;
1295}
1296
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001297static int aureon_cs8415_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1298{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001299 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301 snd_ice1712_save_gpio_status(ice);
1302 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1303 snd_ice1712_restore_gpio_status(ice);
1304 return 0;
1305}
1306
1307/*
1308 * Headphone Amplifier
1309 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001310static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311{
1312 unsigned int tmp, tmp2;
1313
1314 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1315 if (enable)
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001316 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1317 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001318 tmp |= AUREON_HP_SEL;
1319 else
1320 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 else
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001322 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1323 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001324 tmp &= ~AUREON_HP_SEL;
Takashi Iwaic5130272006-05-23 15:46:10 +02001325 else
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001326 tmp &= ~PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 if (tmp != tmp2) {
1328 snd_ice1712_gpio_write(ice, tmp);
1329 return 1;
1330 }
1331 return 0;
1332}
1333
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001334static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335{
1336 unsigned int tmp = snd_ice1712_gpio_read(ice);
1337
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001338 return (tmp & AUREON_HP_SEL) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339}
1340
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001341#define aureon_hpamp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001343static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001345 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
1347 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1348 return 0;
1349}
1350
1351
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001352static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001354 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001356 return aureon_set_headphone_amp(ice, ucontrol->value.integer.value[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357}
1358
1359/*
1360 * Deemphasis
1361 */
1362
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001363#define aureon_deemp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001365static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001367 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1369 return 0;
1370}
1371
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001372static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001374 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 int temp, temp2;
1376 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1377 if (ucontrol->value.integer.value[0])
1378 temp |= 0xf;
1379 else
1380 temp &= ~0xf;
1381 if (temp != temp2) {
1382 wm_put(ice, WM_DAC_CTRL2, temp);
1383 return 1;
1384 }
1385 return 0;
1386}
1387
1388/*
1389 * ADC Oversampling
1390 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001391static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001393 static const char * const texts[2] = { "128x", "64x" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1396 uinfo->count = 1;
1397 uinfo->value.enumerated.items = 2;
1398
1399 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1400 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1401 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1402
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001403 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404}
1405
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001406static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001408 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1410 return 0;
1411}
1412
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001413static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414{
1415 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001416 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418 temp2 = temp = wm_get(ice, WM_MASTER);
1419
1420 if (ucontrol->value.enumerated.item[0])
1421 temp |= 0x8;
1422 else
1423 temp &= ~0x8;
1424
1425 if (temp != temp2) {
1426 wm_put(ice, WM_MASTER, temp);
1427 return 1;
1428 }
1429 return 0;
1430}
1431
1432/*
1433 * mixers
1434 */
1435
Bill Pembertone23e7a12012-12-06 12:35:10 -05001436static struct snd_kcontrol_new aureon_dac_controls[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 {
1438 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1439 .name = "Master Playback Switch",
1440 .info = wm_master_mute_info,
1441 .get = wm_master_mute_get,
1442 .put = wm_master_mute_put
1443 },
1444 {
1445 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001446 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001447 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 .name = "Master Playback Volume",
1449 .info = wm_master_vol_info,
1450 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001451 .put = wm_master_vol_put,
1452 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 },
1454 {
1455 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1456 .name = "Front Playback Switch",
1457 .info = wm_mute_info,
1458 .get = wm_mute_get,
1459 .put = wm_mute_put,
1460 .private_value = (2 << 8) | 0
1461 },
1462 {
1463 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001464 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001465 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 .name = "Front Playback Volume",
1467 .info = wm_vol_info,
1468 .get = wm_vol_get,
1469 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001470 .private_value = (2 << 8) | 0,
1471 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 },
1473 {
1474 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1475 .name = "Rear Playback Switch",
1476 .info = wm_mute_info,
1477 .get = wm_mute_get,
1478 .put = wm_mute_put,
1479 .private_value = (2 << 8) | 2
1480 },
1481 {
1482 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001483 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001484 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 .name = "Rear Playback Volume",
1486 .info = wm_vol_info,
1487 .get = wm_vol_get,
1488 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001489 .private_value = (2 << 8) | 2,
1490 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 },
1492 {
1493 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1494 .name = "Center Playback Switch",
1495 .info = wm_mute_info,
1496 .get = wm_mute_get,
1497 .put = wm_mute_put,
1498 .private_value = (1 << 8) | 4
1499 },
1500 {
1501 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001502 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001503 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 .name = "Center Playback Volume",
1505 .info = wm_vol_info,
1506 .get = wm_vol_get,
1507 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001508 .private_value = (1 << 8) | 4,
1509 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 },
1511 {
1512 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1513 .name = "LFE Playback Switch",
1514 .info = wm_mute_info,
1515 .get = wm_mute_get,
1516 .put = wm_mute_put,
1517 .private_value = (1 << 8) | 5
1518 },
1519 {
1520 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001521 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001522 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 .name = "LFE Playback Volume",
1524 .info = wm_vol_info,
1525 .get = wm_vol_get,
1526 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001527 .private_value = (1 << 8) | 5,
1528 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 },
1530 {
1531 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1532 .name = "Side Playback Switch",
1533 .info = wm_mute_info,
1534 .get = wm_mute_get,
1535 .put = wm_mute_put,
1536 .private_value = (2 << 8) | 6
1537 },
1538 {
1539 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001540 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001541 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 .name = "Side Playback Volume",
1543 .info = wm_vol_info,
1544 .get = wm_vol_get,
1545 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001546 .private_value = (2 << 8) | 6,
1547 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 }
1549};
1550
Bill Pembertone23e7a12012-12-06 12:35:10 -05001551static struct snd_kcontrol_new wm_controls[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001552 {
1553 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 .name = "PCM Playback Switch",
1555 .info = wm_pcm_mute_info,
1556 .get = wm_pcm_mute_get,
1557 .put = wm_pcm_mute_put
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001558 },
1559 {
1560 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001561 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001562 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 .name = "PCM Playback Volume",
1564 .info = wm_pcm_vol_info,
1565 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001566 .put = wm_pcm_vol_put,
1567 .tlv = { .p = db_scale_wm_pcm }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001568 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 {
1570 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1571 .name = "Capture Switch",
1572 .info = wm_adc_mute_info,
1573 .get = wm_adc_mute_get,
1574 .put = wm_adc_mute_put,
1575 },
1576 {
1577 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001578 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001579 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 .name = "Capture Volume",
1581 .info = wm_adc_vol_info,
1582 .get = wm_adc_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001583 .put = wm_adc_vol_put,
1584 .tlv = { .p = db_scale_wm_adc }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 },
1586 {
1587 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1588 .name = "Capture Source",
1589 .info = wm_adc_mux_info,
1590 .get = wm_adc_mux_get,
1591 .put = wm_adc_mux_put,
1592 .private_value = 5
1593 },
1594 {
1595 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1596 .name = "External Amplifier",
1597 .info = aureon_hpamp_info,
1598 .get = aureon_hpamp_get,
1599 .put = aureon_hpamp_put
1600 },
1601 {
1602 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1603 .name = "DAC Deemphasis Switch",
1604 .info = aureon_deemp_info,
1605 .get = aureon_deemp_get,
1606 .put = aureon_deemp_put
1607 },
1608 {
1609 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1610 .name = "ADC Oversampling",
1611 .info = aureon_oversampling_info,
1612 .get = aureon_oversampling_get,
1613 .put = aureon_oversampling_put
1614 }
1615};
1616
Bill Pembertone23e7a12012-12-06 12:35:10 -05001617static struct snd_kcontrol_new ac97_controls[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001618 {
1619 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 .name = "AC97 Playback Switch",
1621 .info = aureon_ac97_mmute_info,
1622 .get = aureon_ac97_mmute_get,
1623 .put = aureon_ac97_mmute_put,
1624 .private_value = AC97_MASTER
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001625 },
1626 {
1627 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001628 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001629 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1630 .name = "AC97 Playback Volume",
1631 .info = aureon_ac97_vol_info,
1632 .get = aureon_ac97_vol_get,
1633 .put = aureon_ac97_vol_put,
1634 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001635 .tlv = { .p = db_scale_ac97_master }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001636 },
1637 {
1638 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1639 .name = "CD Playback Switch",
1640 .info = aureon_ac97_mute_info,
1641 .get = aureon_ac97_mute_get,
1642 .put = aureon_ac97_mute_put,
1643 .private_value = AC97_CD
1644 },
1645 {
1646 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001647 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001648 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1649 .name = "CD Playback Volume",
1650 .info = aureon_ac97_vol_info,
1651 .get = aureon_ac97_vol_get,
1652 .put = aureon_ac97_vol_put,
1653 .private_value = AC97_CD|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001654 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001655 },
1656 {
1657 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1658 .name = "Aux Playback Switch",
1659 .info = aureon_ac97_mute_info,
1660 .get = aureon_ac97_mute_get,
1661 .put = aureon_ac97_mute_put,
1662 .private_value = AC97_AUX,
1663 },
1664 {
1665 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001666 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001667 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1668 .name = "Aux Playback Volume",
1669 .info = aureon_ac97_vol_info,
1670 .get = aureon_ac97_vol_get,
1671 .put = aureon_ac97_vol_put,
1672 .private_value = AC97_AUX|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001673 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001674 },
1675 {
1676 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1677 .name = "Line Playback Switch",
1678 .info = aureon_ac97_mute_info,
1679 .get = aureon_ac97_mute_get,
1680 .put = aureon_ac97_mute_put,
1681 .private_value = AC97_LINE
1682 },
1683 {
1684 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001685 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001686 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1687 .name = "Line Playback Volume",
1688 .info = aureon_ac97_vol_info,
1689 .get = aureon_ac97_vol_get,
1690 .put = aureon_ac97_vol_put,
1691 .private_value = AC97_LINE|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001692 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001693 },
1694 {
1695 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1696 .name = "Mic Playback Switch",
1697 .info = aureon_ac97_mute_info,
1698 .get = aureon_ac97_mute_get,
1699 .put = aureon_ac97_mute_put,
1700 .private_value = AC97_MIC
1701 },
1702 {
1703 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001704 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001705 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1706 .name = "Mic Playback Volume",
1707 .info = aureon_ac97_vol_info,
1708 .get = aureon_ac97_vol_get,
1709 .put = aureon_ac97_vol_put,
1710 .private_value = AC97_MIC,
Takashi Iwaif640c322006-08-30 16:57:37 +02001711 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001712 },
1713 {
1714 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1715 .name = "Mic Boost (+20dB)",
1716 .info = aureon_ac97_micboost_info,
1717 .get = aureon_ac97_micboost_get,
1718 .put = aureon_ac97_micboost_put
1719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720};
1721
Bill Pembertone23e7a12012-12-06 12:35:10 -05001722static struct snd_kcontrol_new universe_ac97_controls[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001723 {
1724 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 .name = "AC97 Playback Switch",
1726 .info = aureon_ac97_mmute_info,
1727 .get = aureon_ac97_mmute_get,
1728 .put = aureon_ac97_mmute_put,
1729 .private_value = AC97_MASTER
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001730 },
1731 {
1732 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001733 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001734 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1735 .name = "AC97 Playback Volume",
1736 .info = aureon_ac97_vol_info,
1737 .get = aureon_ac97_vol_get,
1738 .put = aureon_ac97_vol_put,
1739 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001740 .tlv = { .p = db_scale_ac97_master }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001741 },
1742 {
1743 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1744 .name = "CD Playback Switch",
1745 .info = aureon_ac97_mute_info,
1746 .get = aureon_ac97_mute_get,
1747 .put = aureon_ac97_mute_put,
1748 .private_value = AC97_AUX
1749 },
1750 {
1751 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001752 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001753 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1754 .name = "CD Playback Volume",
1755 .info = aureon_ac97_vol_info,
1756 .get = aureon_ac97_vol_get,
1757 .put = aureon_ac97_vol_put,
1758 .private_value = AC97_AUX|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001759 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001760 },
1761 {
1762 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1763 .name = "Phono Playback Switch",
1764 .info = aureon_ac97_mute_info,
1765 .get = aureon_ac97_mute_get,
1766 .put = aureon_ac97_mute_put,
1767 .private_value = AC97_CD
1768 },
1769 {
1770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001771 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001772 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1773 .name = "Phono Playback Volume",
1774 .info = aureon_ac97_vol_info,
1775 .get = aureon_ac97_vol_get,
1776 .put = aureon_ac97_vol_put,
1777 .private_value = AC97_CD|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001778 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001779 },
1780 {
1781 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1782 .name = "Line Playback Switch",
1783 .info = aureon_ac97_mute_info,
1784 .get = aureon_ac97_mute_get,
1785 .put = aureon_ac97_mute_put,
1786 .private_value = AC97_LINE
1787 },
1788 {
1789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001790 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001791 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1792 .name = "Line Playback Volume",
1793 .info = aureon_ac97_vol_info,
1794 .get = aureon_ac97_vol_get,
1795 .put = aureon_ac97_vol_put,
1796 .private_value = AC97_LINE|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001797 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001798 },
1799 {
1800 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1801 .name = "Mic Playback Switch",
1802 .info = aureon_ac97_mute_info,
1803 .get = aureon_ac97_mute_get,
1804 .put = aureon_ac97_mute_put,
1805 .private_value = AC97_MIC
1806 },
1807 {
1808 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001809 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001810 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1811 .name = "Mic Playback Volume",
1812 .info = aureon_ac97_vol_info,
1813 .get = aureon_ac97_vol_get,
1814 .put = aureon_ac97_vol_put,
1815 .private_value = AC97_MIC,
Takashi Iwaif640c322006-08-30 16:57:37 +02001816 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001817 },
1818 {
1819 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1820 .name = "Mic Boost (+20dB)",
1821 .info = aureon_ac97_micboost_info,
1822 .get = aureon_ac97_micboost_get,
1823 .put = aureon_ac97_micboost_put
1824 },
1825 {
1826 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1827 .name = "Aux Playback Switch",
1828 .info = aureon_ac97_mute_info,
1829 .get = aureon_ac97_mute_get,
1830 .put = aureon_ac97_mute_put,
1831 .private_value = AC97_VIDEO,
1832 },
1833 {
1834 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001835 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001836 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1837 .name = "Aux Playback Volume",
1838 .info = aureon_ac97_vol_info,
1839 .get = aureon_ac97_vol_get,
1840 .put = aureon_ac97_vol_put,
1841 .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001842 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001843 },
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001844 {
1845 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1846 .name = "Aux Source",
1847 .info = aureon_universe_inmux_info,
1848 .get = aureon_universe_inmux_get,
1849 .put = aureon_universe_inmux_put
1850 }
1851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852};
1853
Bill Pembertone23e7a12012-12-06 12:35:10 -05001854static struct snd_kcontrol_new cs8415_controls[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 {
1856 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001857 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 .info = aureon_cs8415_mute_info,
1859 .get = aureon_cs8415_mute_get,
1860 .put = aureon_cs8415_mute_put
1861 },
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001862 {
1863 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1864 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Source",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 .info = aureon_cs8415_mux_info,
1866 .get = aureon_cs8415_mux_get,
1867 .put = aureon_cs8415_mux_put,
1868 },
1869 {
1870 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001871 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ", CAPTURE, DEFAULT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1873 .info = aureon_cs8415_qsub_info,
1874 .get = aureon_cs8415_qsub_get,
1875 },
1876 {
1877 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001878 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1880 .info = aureon_cs8415_spdif_info,
1881 .get = aureon_cs8415_mask_get
1882 },
1883 {
1884 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001885 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1887 .info = aureon_cs8415_spdif_info,
1888 .get = aureon_cs8415_spdif_get
1889 },
1890 {
1891 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001892 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Rate",
1893 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 .info = aureon_cs8415_rate_info,
1895 .get = aureon_cs8415_rate_get
1896 }
1897};
1898
Bill Pembertone23e7a12012-12-06 12:35:10 -05001899static int aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900{
1901 unsigned int i, counts;
1902 int err;
1903
1904 counts = ARRAY_SIZE(aureon_dac_controls);
1905 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1906 counts -= 2; /* no side */
1907 for (i = 0; i < counts; i++) {
1908 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1909 if (err < 0)
1910 return err;
1911 }
1912
1913 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1914 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1915 if (err < 0)
1916 return err;
1917 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001918
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1920 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1921 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1922 if (err < 0)
1923 return err;
1924 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001925 } else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001926 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1928 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1929 if (err < 0)
1930 return err;
1931 }
1932 }
1933
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001934 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1935 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 unsigned char id;
1937 snd_ice1712_save_gpio_status(ice);
1938 id = aureon_cs8415_get(ice, CS8415_ID);
1939 if (id != 0x41)
Takashi Iwai6dfb5af2014-02-25 17:16:16 +01001940 dev_info(ice->card->dev,
1941 "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 else if ((id & 0x0F) != 0x01)
Takashi Iwai6dfb5af2014-02-25 17:16:16 +01001943 dev_info(ice->card->dev,
1944 "Detected unsupported CS8415 rev. (%c)\n",
1945 (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 else {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001947 for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001948 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1950 if (err < 0)
1951 return err;
1952 if (i > 1)
1953 kctl->id.device = ice->pcm->device;
1954 }
1955 }
1956 snd_ice1712_restore_gpio_status(ice);
1957 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 return 0;
1960}
1961
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962/*
Bernhard Urbanae761482010-03-23 04:12:38 +01001963 * reset the chip
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 */
Bernhard Urbanae761482010-03-23 04:12:38 +01001965static int aureon_reset(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001967 static const unsigned short wm_inits_aureon[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 /* These come first to reduce init pop noise */
1969 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1970 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1971 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1972
1973 0x18, 0x000, /* All power-up */
1974
1975 0x16, 0x122, /* I2S, normal polarity, 24bit */
1976 0x17, 0x022, /* 256fs, slave mode */
1977 0x00, 0, /* DAC1 analog mute */
1978 0x01, 0, /* DAC2 analog mute */
1979 0x02, 0, /* DAC3 analog mute */
1980 0x03, 0, /* DAC4 analog mute */
1981 0x04, 0, /* DAC5 analog mute */
1982 0x05, 0, /* DAC6 analog mute */
1983 0x06, 0, /* DAC7 analog mute */
1984 0x07, 0, /* DAC8 analog mute */
1985 0x08, 0x100, /* master analog mute */
1986 0x09, 0xff, /* DAC1 digital full */
1987 0x0a, 0xff, /* DAC2 digital full */
1988 0x0b, 0xff, /* DAC3 digital full */
1989 0x0c, 0xff, /* DAC4 digital full */
1990 0x0d, 0xff, /* DAC5 digital full */
1991 0x0e, 0xff, /* DAC6 digital full */
1992 0x0f, 0xff, /* DAC7 digital full */
1993 0x10, 0xff, /* DAC8 digital full */
1994 0x11, 0x1ff, /* master digital full */
1995 0x12, 0x000, /* phase normal */
1996 0x13, 0x090, /* unmute DAC L/R */
1997 0x14, 0x000, /* all unmute */
1998 0x15, 0x000, /* no deemphasis, no ZFLG */
1999 0x19, 0x000, /* -12dB ADC/L */
2000 0x1a, 0x000, /* -12dB ADC/R */
2001 (unsigned short)-1
2002 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01002003 static const unsigned short wm_inits_prodigy[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004
2005 /* These come first to reduce init pop noise */
2006 0x1b, 0x000, /* ADC Mux */
2007 0x1c, 0x009, /* Out Mux1 */
2008 0x1d, 0x009, /* Out Mux2 */
2009
2010 0x18, 0x000, /* All power-up */
2011
2012 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
2013 0x17, 0x006, /* 128fs, slave mode */
2014
2015 0x00, 0, /* DAC1 analog mute */
2016 0x01, 0, /* DAC2 analog mute */
2017 0x02, 0, /* DAC3 analog mute */
2018 0x03, 0, /* DAC4 analog mute */
2019 0x04, 0, /* DAC5 analog mute */
2020 0x05, 0, /* DAC6 analog mute */
2021 0x06, 0, /* DAC7 analog mute */
2022 0x07, 0, /* DAC8 analog mute */
2023 0x08, 0x100, /* master analog mute */
2024
2025 0x09, 0x7f, /* DAC1 digital full */
2026 0x0a, 0x7f, /* DAC2 digital full */
2027 0x0b, 0x7f, /* DAC3 digital full */
2028 0x0c, 0x7f, /* DAC4 digital full */
2029 0x0d, 0x7f, /* DAC5 digital full */
2030 0x0e, 0x7f, /* DAC6 digital full */
2031 0x0f, 0x7f, /* DAC7 digital full */
2032 0x10, 0x7f, /* DAC8 digital full */
2033 0x11, 0x1FF, /* master digital full */
2034
2035 0x12, 0x000, /* phase normal */
2036 0x13, 0x090, /* unmute DAC L/R */
2037 0x14, 0x000, /* all unmute */
2038 0x15, 0x000, /* no deemphasis, no ZFLG */
2039
2040 0x19, 0x000, /* -12dB ADC/L */
2041 0x1a, 0x000, /* -12dB ADC/R */
2042 (unsigned short)-1
2043
2044 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01002045 static const unsigned short cs_inits[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 0x0441, /* RUN */
2047 0x0180, /* no mute, OMCK output on RMCK pin */
2048 0x0201, /* S/PDIF source on RXP1 */
2049 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
2050 (unsigned short)-1
2051 };
2052 unsigned int tmp;
Takashi Iwai32b47da2007-01-29 15:26:36 +01002053 const unsigned short *p;
Bernhard Urbanae761482010-03-23 04:12:38 +01002054 int err;
2055 struct aureon_spec *spec = ice->spec;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002056
2057 err = aureon_ac97_init(ice);
2058 if (err != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 return err;
2060
2061 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
2062
2063 /* reset the wm codec as the SPI mode */
2064 snd_ice1712_save_gpio_status(ice);
2065 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
2066
2067 tmp = snd_ice1712_gpio_read(ice);
2068 tmp &= ~AUREON_WM_RESET;
2069 snd_ice1712_gpio_write(ice, tmp);
2070 udelay(1);
2071 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
2072 snd_ice1712_gpio_write(ice, tmp);
2073 udelay(1);
2074 tmp |= AUREON_WM_RESET;
2075 snd_ice1712_gpio_write(ice, tmp);
2076 udelay(1);
2077
2078 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002079 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002080 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002081 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 p = wm_inits_prodigy;
2083 else
2084 p = wm_inits_aureon;
2085 for (; *p != (unsigned short)-1; p += 2)
2086 wm_put(ice, p[0], p[1]);
2087
2088 /* initialize CS8415A codec */
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002089 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
2090 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +01002091 for (p = cs_inits; *p != (unsigned short)-1; p++)
2092 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002093 spec->cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
Takashi Iwai45fe7222006-01-13 13:50:16 +01002095 aureon_set_headphone_amp(ice, 1);
2096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
2098 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002099
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002100 /* initialize PCA9554 pin directions & set default input */
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002101 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2102 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Bernhard Urbanae761482010-03-23 04:12:38 +01002103 return 0;
2104}
2105
2106/*
2107 * suspend/resume
2108 */
Takashi Iwaic7561cd2012-08-14 18:12:04 +02002109#ifdef CONFIG_PM_SLEEP
Bernhard Urbanae761482010-03-23 04:12:38 +01002110static int aureon_resume(struct snd_ice1712 *ice)
2111{
2112 struct aureon_spec *spec = ice->spec;
2113 int err, i;
2114
2115 err = aureon_reset(ice);
2116 if (err != 0)
2117 return err;
2118
2119 /* workaround for poking volume with alsamixer after resume:
2120 * just set stored volume again */
2121 for (i = 0; i < ice->num_total_dacs; i++)
2122 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
2123 return 0;
2124}
2125#endif
2126
2127/*
2128 * initialize the chip
2129 */
Bill Pembertone23e7a12012-12-06 12:35:10 -05002130static int aureon_init(struct snd_ice1712 *ice)
Bernhard Urbanae761482010-03-23 04:12:38 +01002131{
2132 struct aureon_spec *spec;
2133 int i, err;
2134
2135 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2136 if (!spec)
2137 return -ENOMEM;
2138 ice->spec = spec;
2139
2140 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
2141 ice->num_total_dacs = 6;
2142 ice->num_total_adcs = 2;
2143 } else {
2144 /* aureon 7.1 and prodigy 7.1 */
2145 ice->num_total_dacs = 8;
2146 ice->num_total_adcs = 2;
2147 }
2148
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002149 /* to remember the register values of CS8415 */
Bernhard Urbanae761482010-03-23 04:12:38 +01002150 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
2151 if (!ice->akm)
2152 return -ENOMEM;
2153 ice->akm_codecs = 1;
2154
2155 err = aureon_reset(ice);
2156 if (err != 0)
2157 return err;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002158
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002159 spec->master[0] = WM_VOL_MUTE;
2160 spec->master[1] = WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 for (i = 0; i < ice->num_total_dacs; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002162 spec->vol[i] = WM_VOL_MUTE;
2163 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 }
2165
Takashi Iwaic7561cd2012-08-14 18:12:04 +02002166#ifdef CONFIG_PM_SLEEP
Bernhard Urbanae761482010-03-23 04:12:38 +01002167 ice->pm_resume = aureon_resume;
2168 ice->pm_suspend_enabled = 1;
2169#endif
2170
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 return 0;
2172}
2173
2174
2175/*
2176 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2177 * hence the driver needs to sets up it properly.
2178 */
2179
Bill Pembertone23e7a12012-12-06 12:35:10 -05002180static unsigned char aureon51_eeprom[] = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002181 [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
2182 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2183 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2184 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2185 [ICE_EEP2_GPIO_DIR] = 0xff,
2186 [ICE_EEP2_GPIO_DIR1] = 0xff,
2187 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2188 [ICE_EEP2_GPIO_MASK] = 0x00,
2189 [ICE_EEP2_GPIO_MASK1] = 0x00,
2190 [ICE_EEP2_GPIO_MASK2] = 0x00,
2191 [ICE_EEP2_GPIO_STATE] = 0x00,
2192 [ICE_EEP2_GPIO_STATE1] = 0x00,
2193 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194};
2195
Bill Pembertone23e7a12012-12-06 12:35:10 -05002196static unsigned char aureon71_eeprom[] = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002197 [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
2198 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2199 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2200 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2201 [ICE_EEP2_GPIO_DIR] = 0xff,
2202 [ICE_EEP2_GPIO_DIR1] = 0xff,
2203 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2204 [ICE_EEP2_GPIO_MASK] = 0x00,
2205 [ICE_EEP2_GPIO_MASK1] = 0x00,
2206 [ICE_EEP2_GPIO_MASK2] = 0x00,
2207 [ICE_EEP2_GPIO_STATE] = 0x00,
2208 [ICE_EEP2_GPIO_STATE1] = 0x00,
2209 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210};
Takashi Iwai189bc172007-01-29 15:25:40 +01002211#define prodigy71_eeprom aureon71_eeprom
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Bill Pembertone23e7a12012-12-06 12:35:10 -05002213static unsigned char aureon71_universe_eeprom[] = {
Maximilian Rehkopfc1805dd2008-08-29 14:11:10 +02002214 [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC,
2215 * 4DACs
2216 */
2217 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2218 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2219 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2220 [ICE_EEP2_GPIO_DIR] = 0xff,
2221 [ICE_EEP2_GPIO_DIR1] = 0xff,
2222 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2223 [ICE_EEP2_GPIO_MASK] = 0x00,
2224 [ICE_EEP2_GPIO_MASK1] = 0x00,
2225 [ICE_EEP2_GPIO_MASK2] = 0x00,
2226 [ICE_EEP2_GPIO_STATE] = 0x00,
2227 [ICE_EEP2_GPIO_STATE1] = 0x00,
2228 [ICE_EEP2_GPIO_STATE2] = 0x00,
2229};
2230
Bill Pembertone23e7a12012-12-06 12:35:10 -05002231static unsigned char prodigy71lt_eeprom[] = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002232 [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
2233 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2234 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2235 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2236 [ICE_EEP2_GPIO_DIR] = 0xff,
2237 [ICE_EEP2_GPIO_DIR1] = 0xff,
2238 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2239 [ICE_EEP2_GPIO_MASK] = 0x00,
2240 [ICE_EEP2_GPIO_MASK1] = 0x00,
2241 [ICE_EEP2_GPIO_MASK2] = 0x00,
2242 [ICE_EEP2_GPIO_STATE] = 0x00,
2243 [ICE_EEP2_GPIO_STATE1] = 0x00,
2244 [ICE_EEP2_GPIO_STATE2] = 0x00,
Takashi Iwai45fe7222006-01-13 13:50:16 +01002245};
Takashi Iwai189bc172007-01-29 15:25:40 +01002246#define prodigy71xt_eeprom prodigy71lt_eeprom
Takashi Iwai45fe7222006-01-13 13:50:16 +01002247
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248/* entry point */
Bill Pembertone23e7a12012-12-06 12:35:10 -05002249struct snd_ice1712_card_info snd_vt1724_aureon_cards[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 {
2251 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2252 .name = "Terratec Aureon 5.1-Sky",
2253 .model = "aureon51",
2254 .chip_init = aureon_init,
2255 .build_controls = aureon_add_controls,
2256 .eeprom_size = sizeof(aureon51_eeprom),
2257 .eeprom_data = aureon51_eeprom,
2258 .driver = "Aureon51",
2259 },
2260 {
2261 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2262 .name = "Terratec Aureon 7.1-Space",
2263 .model = "aureon71",
2264 .chip_init = aureon_init,
2265 .build_controls = aureon_add_controls,
2266 .eeprom_size = sizeof(aureon71_eeprom),
2267 .eeprom_data = aureon71_eeprom,
2268 .driver = "Aureon71",
2269 },
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002270 {
2271 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2272 .name = "Terratec Aureon 7.1-Universe",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 .model = "universe",
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002274 .chip_init = aureon_init,
2275 .build_controls = aureon_add_controls,
Maximilian Rehkopfc1805dd2008-08-29 14:11:10 +02002276 .eeprom_size = sizeof(aureon71_universe_eeprom),
2277 .eeprom_data = aureon71_universe_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002278 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 },
2280 {
2281 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2282 .name = "Audiotrak Prodigy 7.1",
2283 .model = "prodigy71",
2284 .chip_init = aureon_init,
2285 .build_controls = aureon_add_controls,
2286 .eeprom_size = sizeof(prodigy71_eeprom),
2287 .eeprom_data = prodigy71_eeprom,
2288 .driver = "Prodigy71", /* should be identical with Aureon71 */
2289 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002290 {
2291 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2292 .name = "Audiotrak Prodigy 7.1 LT",
2293 .model = "prodigy71lt",
2294 .chip_init = aureon_init,
2295 .build_controls = aureon_add_controls,
2296 .eeprom_size = sizeof(prodigy71lt_eeprom),
2297 .eeprom_data = prodigy71lt_eeprom,
2298 .driver = "Prodigy71LT",
2299 },
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002300 {
2301 .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
2302 .name = "Audiotrak Prodigy 7.1 XT",
2303 .model = "prodigy71xt",
2304 .chip_init = aureon_init,
2305 .build_controls = aureon_add_controls,
2306 .eeprom_size = sizeof(prodigy71xt_eeprom),
2307 .eeprom_data = prodigy71xt_eeprom,
2308 .driver = "Prodigy71LT",
2309 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 { } /* terminator */
2311};