blob: c9411dfff5a4deee94bad34e6da4b0b9d7ca1479 [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
Takashi Iwai597da2e2014-10-20 18:18:50 +0200208 return snd_ctl_enum_info(uinfo, 1, 3, texts);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200209}
210
211static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
212 struct snd_ctl_elem_value *ucontrol)
213{
214 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100215 struct aureon_spec *spec = ice->spec;
216 ucontrol->value.enumerated.item[0] = spec->pca9554_out;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200217 return 0;
218}
219
220static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
221 struct snd_ctl_elem_value *ucontrol)
222{
223 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100224 struct aureon_spec *spec = ice->spec;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200225 unsigned char oval, nval;
226 int change;
227
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100228 nval = ucontrol->value.enumerated.item[0];
229 if (nval >= 3)
230 return -EINVAL;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200231 snd_ice1712_save_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100232 oval = spec->pca9554_out;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400233 change = (oval != nval);
234 if (change) {
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200235 aureon_pca9554_write(ice, PCA9554_OUT, nval);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100236 spec->pca9554_out = nval;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200237 }
238 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200239 return change;
240}
241
242
243static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
244 unsigned short val)
245{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100246 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 unsigned int tmp;
248
249 /* Send address to XILINX chip */
250 tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F);
251 snd_ice1712_gpio_write(ice, tmp);
252 udelay(10);
253 tmp |= AUREON_AC97_ADDR;
254 snd_ice1712_gpio_write(ice, tmp);
255 udelay(10);
256 tmp &= ~AUREON_AC97_ADDR;
257 snd_ice1712_gpio_write(ice, tmp);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400258 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 /* Send low-order byte to XILINX chip */
261 tmp &= ~AUREON_AC97_DATA_MASK;
262 tmp |= val & AUREON_AC97_DATA_MASK;
263 snd_ice1712_gpio_write(ice, tmp);
264 udelay(10);
265 tmp |= AUREON_AC97_DATA_LOW;
266 snd_ice1712_gpio_write(ice, tmp);
267 udelay(10);
268 tmp &= ~AUREON_AC97_DATA_LOW;
269 snd_ice1712_gpio_write(ice, tmp);
270 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 /* Send high-order byte to XILINX chip */
273 tmp &= ~AUREON_AC97_DATA_MASK;
274 tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
275
276 snd_ice1712_gpio_write(ice, tmp);
277 udelay(10);
278 tmp |= AUREON_AC97_DATA_HIGH;
279 snd_ice1712_gpio_write(ice, tmp);
280 udelay(10);
281 tmp &= ~AUREON_AC97_DATA_HIGH;
282 snd_ice1712_gpio_write(ice, tmp);
283 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 /* Instruct XILINX chip to parse the data to the STAC9744 chip */
286 tmp |= AUREON_AC97_COMMIT;
287 snd_ice1712_gpio_write(ice, tmp);
288 udelay(10);
289 tmp &= ~AUREON_AC97_COMMIT;
290 snd_ice1712_gpio_write(ice, tmp);
291 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 /* Store the data in out private buffer */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100294 spec->stac9744[(reg & 0x7F) >> 1] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
296
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100297static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100299 struct aureon_spec *spec = ice->spec;
300 return spec->stac9744[(reg & 0x7F) >> 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
303/*
304 * Initialize STAC9744 chip
305 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400306static int aureon_ac97_init(struct snd_ice1712 *ice)
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200307{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100308 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 int i;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100310 static const unsigned short ac97_defaults[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 0x00, 0x9640,
312 0x02, 0x8000,
313 0x04, 0x8000,
314 0x06, 0x8000,
315 0x0C, 0x8008,
316 0x0E, 0x8008,
317 0x10, 0x8808,
318 0x12, 0x8808,
319 0x14, 0x8808,
320 0x16, 0x8808,
321 0x18, 0x8808,
322 0x1C, 0x8000,
323 0x26, 0x000F,
324 0x28, 0x0201,
325 0x2C, 0xBB80,
326 0x32, 0xBB80,
327 0x7C, 0x8384,
328 0x7E, 0x7644,
329 (unsigned short)-1
330 };
331 unsigned int tmp;
332
333 /* Cold reset */
334 tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
335 snd_ice1712_gpio_write(ice, tmp);
336 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 tmp &= ~AUREON_AC97_RESET;
339 snd_ice1712_gpio_write(ice, tmp);
340 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 tmp |= AUREON_AC97_RESET;
343 snd_ice1712_gpio_write(ice, tmp);
344 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400345
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100346 memset(&spec->stac9744, 0, sizeof(spec->stac9744));
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400347 for (i = 0; ac97_defaults[i] != (unsigned short)-1; i += 2)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100348 spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400349
350 /* Unmute AC'97 master volume permanently - muting is done by WM8770 */
351 aureon_ac97_write(ice, AC97_MASTER, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
353 return 0;
354}
355
356#define AUREON_AC97_STEREO 0x80
357
358/*
359 * AC'97 volume controls
360 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100361static int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
363 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
364 uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1;
365 uinfo->value.integer.min = 0;
366 uinfo->value.integer.max = 31;
367 return 0;
368}
369
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100370static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100372 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 unsigned short vol;
374
Ingo Molnar62932df2006-01-16 16:34:20 +0100375 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
378 ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
379 if (kcontrol->private_value & AUREON_AC97_STEREO)
380 ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
381
Ingo Molnar62932df2006-01-16 16:34:20 +0100382 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 return 0;
384}
385
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100386static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100388 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 unsigned short ovol, nvol;
390 int change;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 snd_ice1712_save_gpio_status(ice);
393
394 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
395 nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F;
396 if (kcontrol->private_value & AUREON_AC97_STEREO)
397 nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
398 nvol |= ovol & ~0x1F1F;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400399
400 change = (ovol != nvol);
401 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
403
404 snd_ice1712_restore_gpio_status(ice);
405
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400406 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407}
408
409/*
410 * AC'97 mute controls
411 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200412#define aureon_ac97_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100414static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100416 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Ingo Molnar62932df2006-01-16 16:34:20 +0100418 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400420 ucontrol->value.integer.value[0] = aureon_ac97_read(ice,
421 kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Ingo Molnar62932df2006-01-16 16:34:20 +0100423 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 return 0;
425}
426
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100427static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100429 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 unsigned short ovol, nvol;
431 int change;
432
433 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400436 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~0x8000);
437
438 change = (ovol != nvol);
439 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 snd_ice1712_restore_gpio_status(ice);
443
444 return change;
445}
446
447/*
448 * AC'97 mute controls
449 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200450#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100452static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100454 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Ingo Molnar62932df2006-01-16 16:34:20 +0100456 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
458 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
459
Ingo Molnar62932df2006-01-16 16:34:20 +0100460 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 return 0;
462}
463
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100464static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100466 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 unsigned short ovol, nvol;
468 int change;
469
470 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 ovol = aureon_ac97_read(ice, AC97_MIC);
473 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400474
475 change = (ovol != nvol);
476 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 aureon_ac97_write(ice, AC97_MIC, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 snd_ice1712_restore_gpio_status(ice);
480
481 return change;
482}
483
484/*
485 * write data in the SPI mode
486 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100487static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
489 unsigned int tmp;
490 int i;
Takashi Iwai45fe7222006-01-13 13:50:16 +0100491 unsigned int mosi, clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 tmp = snd_ice1712_gpio_read(ice);
494
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100495 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
496 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100497 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
498 mosi = PRODIGY_SPI_MOSI;
499 clk = PRODIGY_SPI_CLK;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400500 } else {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100501 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
502 AUREON_WM_CS|AUREON_CS8415_CS));
503 mosi = AUREON_SPI_MOSI;
504 clk = AUREON_SPI_CLK;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400505
Takashi Iwai45fe7222006-01-13 13:50:16 +0100506 tmp |= AUREON_WM_RW;
507 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 tmp &= ~cs;
510 snd_ice1712_gpio_write(ice, tmp);
511 udelay(1);
512
513 for (i = bits - 1; i >= 0; i--) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100514 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 snd_ice1712_gpio_write(ice, tmp);
516 udelay(1);
517 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100518 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100520 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 snd_ice1712_gpio_write(ice, tmp);
522 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100523 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 snd_ice1712_gpio_write(ice, tmp);
525 udelay(1);
526 }
527
Takashi Iwai45fe7222006-01-13 13:50:16 +0100528 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 tmp |= cs;
530 snd_ice1712_gpio_write(ice, tmp);
531 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100532 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 snd_ice1712_gpio_write(ice, tmp);
534 udelay(1);
535}
536
537/*
538 * Read data in SPI mode
539 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400540static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs,
541 unsigned int data, int bits, unsigned char *buffer, int size)
542{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 int i, j;
544 unsigned int tmp;
545
546 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
547 snd_ice1712_gpio_write(ice, tmp);
548 tmp &= ~cs;
549 snd_ice1712_gpio_write(ice, tmp);
550 udelay(1);
551
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400552 for (i = bits-1; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 if (data & (1 << i))
554 tmp |= AUREON_SPI_MOSI;
555 else
556 tmp &= ~AUREON_SPI_MOSI;
557 snd_ice1712_gpio_write(ice, tmp);
558 udelay(1);
559
560 tmp |= AUREON_SPI_CLK;
561 snd_ice1712_gpio_write(ice, tmp);
562 udelay(1);
563
564 tmp &= ~AUREON_SPI_CLK;
565 snd_ice1712_gpio_write(ice, tmp);
566 udelay(1);
567 }
568
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400569 for (j = 0; j < size; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 unsigned char outdata = 0;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400571 for (i = 7; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 tmp = snd_ice1712_gpio_read(ice);
573 outdata <<= 1;
574 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
575 udelay(1);
576
577 tmp |= AUREON_SPI_CLK;
578 snd_ice1712_gpio_write(ice, tmp);
579 udelay(1);
580
581 tmp &= ~AUREON_SPI_CLK;
582 snd_ice1712_gpio_write(ice, tmp);
583 udelay(1);
584 }
585 buffer[j] = outdata;
586 }
587
588 tmp |= cs;
589 snd_ice1712_gpio_write(ice, tmp);
590}
591
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400592static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg)
593{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 unsigned char val;
595 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
596 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
597 return val;
598}
599
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400600static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg,
601 unsigned char *buffer, int size)
602{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
604 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
605}
606
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400607static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg,
608 unsigned char val)
609{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
611}
612
613/*
614 * get the current register value of WM codec
615 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100616static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
618 reg <<= 1;
619 return ((unsigned short)ice->akm[0].images[reg] << 8) |
620 ice->akm[0].images[reg + 1];
621}
622
623/*
624 * set the register value of WM codec
625 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100626static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100628 aureon_spi_write(ice,
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100629 ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
630 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
631 PRODIGY_WM_CS : AUREON_WM_CS),
Takashi Iwai45fe7222006-01-13 13:50:16 +0100632 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633}
634
635/*
636 * set the register value of WM codec and remember it
637 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100638static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
640 wm_put_nocache(ice, reg, val);
641 reg <<= 1;
642 ice->akm[0].images[reg] = val >> 8;
643 ice->akm[0].images[reg + 1] = val;
644}
645
646/*
647 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200648#define aureon_mono_bool_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650/*
651 * AC'97 master playback mute controls (Mute on WM8770 chip)
652 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200653#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100655static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100657 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Ingo Molnar62932df2006-01-16 16:34:20 +0100659 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
662
Ingo Molnar62932df2006-01-16 16:34:20 +0100663 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 return 0;
665}
666
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400667static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
668{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100669 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 unsigned short ovol, nvol;
671 int change;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 ovol = wm_get(ice, WM_OUT_MUX1);
676 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400677 change = (ovol != nvol);
678 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 wm_put(ice, WM_OUT_MUX1, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 snd_ice1712_restore_gpio_status(ice);
682
683 return change;
684}
685
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100686static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -10000, 100, 1);
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100687static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
688static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
689static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
690static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
Takashi Iwaif640c322006-08-30 16:57:37 +0200691
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100692#define WM_VOL_MAX 100
693#define WM_VOL_CNT 101 /* 0dB .. -100dB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694#define WM_VOL_MUTE 0x8000
695
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100696static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697{
698 unsigned char nvol;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400699
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100700 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 nvol = 0;
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100702 } else {
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100703 nvol = ((vol % WM_VOL_CNT) * (master % WM_VOL_CNT)) /
704 WM_VOL_MAX;
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100705 nvol += 0x1b;
706 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 wm_put(ice, index, nvol);
709 wm_put_nocache(ice, index, 0x180 | nvol);
710}
711
712/*
713 * DAC mute control
714 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200715#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100717static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100719 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Ingo Molnar62932df2006-01-16 16:34:20 +0100721 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100723 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return 0;
725}
726
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100727static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100729 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 unsigned short nval, oval;
731 int change;
732
733 snd_ice1712_save_gpio_status(ice);
734 oval = wm_get(ice, WM_MUTE);
735 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400736 change = (oval != nval);
737 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 wm_put(ice, WM_MUTE, nval);
739 snd_ice1712_restore_gpio_status(ice);
740
741 return change;
742}
743
744/*
745 * Master volume attenuation mixer control
746 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100747static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
749 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
750 uinfo->count = 2;
751 uinfo->value.integer.min = 0;
752 uinfo->value.integer.max = WM_VOL_MAX;
753 return 0;
754}
755
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100756static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100758 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100759 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 int i;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400761 for (i = 0; i < 2; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100762 ucontrol->value.integer.value[i] =
763 spec->master[i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return 0;
765}
766
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100767static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100769 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100770 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 int ch, change = 0;
772
773 snd_ice1712_save_gpio_status(ice);
774 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100775 unsigned int vol = ucontrol->value.integer.value[ch];
776 if (vol > WM_VOL_MAX)
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100777 vol = WM_VOL_MAX;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100778 vol |= spec->master[ch] & WM_VOL_MUTE;
779 if (vol != spec->master[ch]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100781 spec->master[ch] = vol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
783 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100784 spec->vol[dac + ch],
785 spec->master[ch]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 change = 1;
787 }
788 }
789 snd_ice1712_restore_gpio_status(ice);
790 return change;
791}
792
793/*
794 * DAC volume attenuation mixer control
795 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100796static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797{
798 int voices = kcontrol->private_value >> 8;
799 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
800 uinfo->count = voices;
801 uinfo->value.integer.min = 0; /* mute (-101dB) */
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100802 uinfo->value.integer.max = WM_VOL_MAX; /* 0dB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return 0;
804}
805
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100806static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100808 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100809 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 int i, ofs, voices;
811
812 voices = kcontrol->private_value >> 8;
813 ofs = kcontrol->private_value & 0xff;
814 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100815 ucontrol->value.integer.value[i] =
816 spec->vol[ofs+i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 return 0;
818}
819
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100820static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100822 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100823 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 int i, idx, ofs, voices;
825 int change = 0;
826
827 voices = kcontrol->private_value >> 8;
828 ofs = kcontrol->private_value & 0xff;
829 snd_ice1712_save_gpio_status(ice);
830 for (i = 0; i < voices; i++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100831 unsigned int vol = ucontrol->value.integer.value[i];
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100832 if (vol > WM_VOL_MAX)
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100833 vol = WM_VOL_MAX;
834 vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100835 if (vol != spec->vol[ofs+i]) {
836 spec->vol[ofs+i] = vol;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100837 idx = WM_DAC_ATTEN + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100838 wm_set_vol(ice, idx, spec->vol[ofs + i],
839 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 change = 1;
841 }
842 }
843 snd_ice1712_restore_gpio_status(ice);
844 return change;
845}
846
847/*
848 * WM8770 mute control
849 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400850static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
851{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
853 uinfo->count = kcontrol->private_value >> 8;
854 uinfo->value.integer.min = 0;
855 uinfo->value.integer.max = 1;
856 return 0;
857}
858
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100859static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100861 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100862 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 int voices, ofs, i;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400864
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 voices = kcontrol->private_value >> 8;
866 ofs = kcontrol->private_value & 0xFF;
867
868 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100869 ucontrol->value.integer.value[i] =
870 (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return 0;
872}
873
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100874static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100876 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100877 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 int change = 0, voices, ofs, i;
879
880 voices = kcontrol->private_value >> 8;
881 ofs = kcontrol->private_value & 0xFF;
882
883 snd_ice1712_save_gpio_status(ice);
884 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100885 int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 if (ucontrol->value.integer.value[i] != val) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100887 spec->vol[ofs + i] &= ~WM_VOL_MUTE;
888 spec->vol[ofs + i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100890 wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
891 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 change = 1;
893 }
894 }
895 snd_ice1712_restore_gpio_status(ice);
896
897 return change;
898}
899
900/*
901 * WM8770 master mute control
902 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200903#define wm_master_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100905static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100907 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100908 struct aureon_spec *spec = ice->spec;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400909
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100910 ucontrol->value.integer.value[0] =
911 (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
912 ucontrol->value.integer.value[1] =
913 (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 return 0;
915}
916
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100917static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100919 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100920 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 int change = 0, i;
922
923 snd_ice1712_save_gpio_status(ice);
924 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100925 int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 if (ucontrol->value.integer.value[i] != val) {
927 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100928 spec->master[i] &= ~WM_VOL_MUTE;
929 spec->master[i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
931 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
932 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100933 spec->vol[dac + i],
934 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 change = 1;
936 }
937 }
938 snd_ice1712_restore_gpio_status(ice);
939
940 return change;
941}
942
943/* digital master volume */
944#define PCM_0dB 0xff
945#define PCM_RES 128 /* -64dB */
946#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100947static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
949 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
950 uinfo->count = 1;
951 uinfo->value.integer.min = 0; /* mute (-64dB) */
952 uinfo->value.integer.max = PCM_RES; /* 0dB */
953 return 0;
954}
955
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100956static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100958 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 unsigned short val;
960
Ingo Molnar62932df2006-01-16 16:34:20 +0100961 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
963 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
964 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100965 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 return 0;
967}
968
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100969static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100971 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 unsigned short ovol, nvol;
973 int change = 0;
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100976 if (nvol > PCM_RES)
977 return -EINVAL;
978 snd_ice1712_save_gpio_status(ice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
980 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
981 if (ovol != nvol) {
982 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
983 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
984 change = 1;
985 }
986 snd_ice1712_restore_gpio_status(ice);
987 return change;
988}
989
990/*
991 * ADC mute control
992 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200993#define wm_adc_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100995static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100997 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 unsigned short val;
999 int i;
1000
Ingo Molnar62932df2006-01-16 16:34:20 +01001001 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 for (i = 0; i < 2; i++) {
1003 val = wm_get(ice, WM_ADC_GAIN + i);
1004 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
1005 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001006 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return 0;
1008}
1009
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001010static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001012 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 unsigned short new, old;
1014 int i, change = 0;
1015
1016 snd_ice1712_save_gpio_status(ice);
1017 for (i = 0; i < 2; i++) {
1018 old = wm_get(ice, WM_ADC_GAIN + i);
1019 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
1020 if (new != old) {
1021 wm_put(ice, WM_ADC_GAIN + i, new);
1022 change = 1;
1023 }
1024 }
1025 snd_ice1712_restore_gpio_status(ice);
1026
1027 return change;
1028}
1029
1030/*
1031 * ADC gain mixer control
1032 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001033static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034{
1035 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1036 uinfo->count = 2;
1037 uinfo->value.integer.min = 0; /* -12dB */
1038 uinfo->value.integer.max = 0x1f; /* 19dB */
1039 return 0;
1040}
1041
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001042static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001044 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 int i, idx;
1046 unsigned short vol;
1047
Ingo Molnar62932df2006-01-16 16:34:20 +01001048 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 for (i = 0; i < 2; i++) {
1050 idx = WM_ADC_GAIN + i;
1051 vol = wm_get(ice, idx) & 0x1f;
1052 ucontrol->value.integer.value[i] = vol;
1053 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001054 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 return 0;
1056}
1057
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001058static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001060 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 int i, idx;
1062 unsigned short ovol, nvol;
1063 int change = 0;
1064
1065 snd_ice1712_save_gpio_status(ice);
1066 for (i = 0; i < 2; i++) {
1067 idx = WM_ADC_GAIN + i;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +01001068 nvol = ucontrol->value.integer.value[i] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 ovol = wm_get(ice, idx);
1070 if ((ovol & 0x1f) != nvol) {
1071 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1072 change = 1;
1073 }
1074 }
1075 snd_ice1712_restore_gpio_status(ice);
1076 return change;
1077}
1078
1079/*
1080 * ADC input mux mixer control
1081 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001082static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001084 static const char * const texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001085 "CD", /* AIN1 */
1086 "Aux", /* AIN2 */
1087 "Line", /* AIN3 */
1088 "Mic", /* AIN4 */
1089 "AC97" /* AIN5 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001091 static const char * const universe_texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001092 "Aux1", /* AIN1 */
1093 "CD", /* AIN2 */
1094 "Phono", /* AIN3 */
1095 "Line", /* AIN4 */
1096 "Aux2", /* AIN5 */
1097 "Mic", /* AIN6 */
1098 "Aux3", /* AIN7 */
1099 "AC97" /* AIN8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001101 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Takashi Iwai597da2e2014-10-20 18:18:50 +02001103 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE)
1104 return snd_ctl_enum_info(uinfo, 2, 8, universe_texts);
1105 else
1106 return snd_ctl_enum_info(uinfo, 2, 5, texts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107}
1108
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001109static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001111 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 unsigned short val;
1113
Ingo Molnar62932df2006-01-16 16:34:20 +01001114 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001116 ucontrol->value.enumerated.item[0] = val & 7;
1117 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001118 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 return 0;
1120}
1121
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001122static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001124 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 unsigned short oval, nval;
1126 int change;
1127
1128 snd_ice1712_save_gpio_status(ice);
1129 oval = wm_get(ice, WM_ADC_MUX);
1130 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001131 nval |= ucontrol->value.enumerated.item[0] & 7;
1132 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 change = (oval != nval);
1134 if (change)
1135 wm_put(ice, WM_ADC_MUX, nval);
1136 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001137 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138}
1139
1140/*
1141 * CS8415 Input mux
1142 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001143static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001145 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai32b47da2007-01-29 15:26:36 +01001146 static const char * const aureon_texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001147 "CD", /* RXP0 */
1148 "Optical" /* RXP1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001150 static const char * const prodigy_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 "CD",
1152 "Coax"
1153 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
Takashi Iwai597da2e2014-10-20 18:18:50 +02001155 return snd_ctl_enum_info(uinfo, 1, 2, prodigy_texts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 else
Takashi Iwai597da2e2014-10-20 18:18:50 +02001157 return snd_ctl_enum_info(uinfo, 1, 2, aureon_texts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158}
1159
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001160static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001162 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001163 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001165 /* snd_ice1712_save_gpio_status(ice); */
1166 /* val = aureon_cs8415_get(ice, CS8415_CTRL2); */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001167 ucontrol->value.enumerated.item[0] = spec->cs8415_mux;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001168 /* snd_ice1712_restore_gpio_status(ice); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 return 0;
1170}
1171
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001172static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001174 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001175 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 unsigned short oval, nval;
1177 int change;
1178
1179 snd_ice1712_save_gpio_status(ice);
1180 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1181 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001182 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 change = (oval != nval);
1184 if (change)
1185 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1186 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001187 spec->cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 return change;
1189}
1190
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001191static int aureon_cs8415_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192{
1193 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1194 uinfo->count = 1;
1195 uinfo->value.integer.min = 0;
1196 uinfo->value.integer.max = 192000;
1197 return 0;
1198}
1199
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001200static int aureon_cs8415_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001202 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 unsigned char ratio;
1204 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1205 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1206 return 0;
1207}
1208
1209/*
1210 * CS8415A Mute
1211 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001212#define aureon_cs8415_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001214static int aureon_cs8415_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001216 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 snd_ice1712_save_gpio_status(ice);
1218 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1219 snd_ice1712_restore_gpio_status(ice);
1220 return 0;
1221}
1222
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001223static int aureon_cs8415_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001225 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 unsigned char oval, nval;
1227 int change;
1228 snd_ice1712_save_gpio_status(ice);
1229 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1230 if (ucontrol->value.integer.value[0])
1231 nval = oval & ~0x20;
1232 else
1233 nval = oval | 0x20;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001234 change = (oval != nval);
1235 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1237 snd_ice1712_restore_gpio_status(ice);
1238 return change;
1239}
1240
1241/*
1242 * CS8415A Q-Sub info
1243 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001244static int aureon_cs8415_qsub_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1245{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1247 uinfo->count = 10;
1248 return 0;
1249}
1250
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001251static int aureon_cs8415_qsub_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1252{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001253 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 snd_ice1712_save_gpio_status(ice);
1256 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1257 snd_ice1712_restore_gpio_status(ice);
1258
1259 return 0;
1260}
1261
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001262static int aureon_cs8415_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1263{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1265 uinfo->count = 1;
1266 return 0;
1267}
1268
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001269static int aureon_cs8415_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1270{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 memset(ucontrol->value.iec958.status, 0xFF, 24);
1272 return 0;
1273}
1274
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001275static int aureon_cs8415_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1276{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001277 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
1279 snd_ice1712_save_gpio_status(ice);
1280 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1281 snd_ice1712_restore_gpio_status(ice);
1282 return 0;
1283}
1284
1285/*
1286 * Headphone Amplifier
1287 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001288static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
1290 unsigned int tmp, tmp2;
1291
1292 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1293 if (enable)
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001294 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1295 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001296 tmp |= AUREON_HP_SEL;
1297 else
1298 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 else
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001300 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1301 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001302 tmp &= ~AUREON_HP_SEL;
Takashi Iwaic5130272006-05-23 15:46:10 +02001303 else
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001304 tmp &= ~PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 if (tmp != tmp2) {
1306 snd_ice1712_gpio_write(ice, tmp);
1307 return 1;
1308 }
1309 return 0;
1310}
1311
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001312static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313{
1314 unsigned int tmp = snd_ice1712_gpio_read(ice);
1315
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001316 return (tmp & AUREON_HP_SEL) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317}
1318
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001319#define aureon_hpamp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001321static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001323 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
1325 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1326 return 0;
1327}
1328
1329
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001330static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001332 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001334 return aureon_set_headphone_amp(ice, ucontrol->value.integer.value[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335}
1336
1337/*
1338 * Deemphasis
1339 */
1340
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001341#define aureon_deemp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001343static int aureon_deemp_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 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1347 return 0;
1348}
1349
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001350static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001352 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 int temp, temp2;
1354 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1355 if (ucontrol->value.integer.value[0])
1356 temp |= 0xf;
1357 else
1358 temp &= ~0xf;
1359 if (temp != temp2) {
1360 wm_put(ice, WM_DAC_CTRL2, temp);
1361 return 1;
1362 }
1363 return 0;
1364}
1365
1366/*
1367 * ADC Oversampling
1368 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001369static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001371 static const char * const texts[2] = { "128x", "64x" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Takashi Iwai597da2e2014-10-20 18:18:50 +02001373 return snd_ctl_enum_info(uinfo, 1, 2, texts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374}
1375
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001376static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001378 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1380 return 0;
1381}
1382
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001383static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384{
1385 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001386 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 temp2 = temp = wm_get(ice, WM_MASTER);
1389
1390 if (ucontrol->value.enumerated.item[0])
1391 temp |= 0x8;
1392 else
1393 temp &= ~0x8;
1394
1395 if (temp != temp2) {
1396 wm_put(ice, WM_MASTER, temp);
1397 return 1;
1398 }
1399 return 0;
1400}
1401
1402/*
1403 * mixers
1404 */
1405
Bill Pembertone23e7a12012-12-06 12:35:10 -05001406static struct snd_kcontrol_new aureon_dac_controls[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 {
1408 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1409 .name = "Master Playback Switch",
1410 .info = wm_master_mute_info,
1411 .get = wm_master_mute_get,
1412 .put = wm_master_mute_put
1413 },
1414 {
1415 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001416 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001417 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 .name = "Master Playback Volume",
1419 .info = wm_master_vol_info,
1420 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001421 .put = wm_master_vol_put,
1422 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 },
1424 {
1425 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1426 .name = "Front Playback Switch",
1427 .info = wm_mute_info,
1428 .get = wm_mute_get,
1429 .put = wm_mute_put,
1430 .private_value = (2 << 8) | 0
1431 },
1432 {
1433 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001434 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001435 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 .name = "Front Playback Volume",
1437 .info = wm_vol_info,
1438 .get = wm_vol_get,
1439 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001440 .private_value = (2 << 8) | 0,
1441 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 },
1443 {
1444 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1445 .name = "Rear Playback Switch",
1446 .info = wm_mute_info,
1447 .get = wm_mute_get,
1448 .put = wm_mute_put,
1449 .private_value = (2 << 8) | 2
1450 },
1451 {
1452 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001453 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001454 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 .name = "Rear Playback Volume",
1456 .info = wm_vol_info,
1457 .get = wm_vol_get,
1458 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001459 .private_value = (2 << 8) | 2,
1460 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 },
1462 {
1463 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1464 .name = "Center Playback Switch",
1465 .info = wm_mute_info,
1466 .get = wm_mute_get,
1467 .put = wm_mute_put,
1468 .private_value = (1 << 8) | 4
1469 },
1470 {
1471 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001472 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001473 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 .name = "Center Playback Volume",
1475 .info = wm_vol_info,
1476 .get = wm_vol_get,
1477 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001478 .private_value = (1 << 8) | 4,
1479 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 },
1481 {
1482 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1483 .name = "LFE Playback Switch",
1484 .info = wm_mute_info,
1485 .get = wm_mute_get,
1486 .put = wm_mute_put,
1487 .private_value = (1 << 8) | 5
1488 },
1489 {
1490 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001491 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001492 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 .name = "LFE Playback Volume",
1494 .info = wm_vol_info,
1495 .get = wm_vol_get,
1496 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001497 .private_value = (1 << 8) | 5,
1498 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 },
1500 {
1501 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1502 .name = "Side Playback Switch",
1503 .info = wm_mute_info,
1504 .get = wm_mute_get,
1505 .put = wm_mute_put,
1506 .private_value = (2 << 8) | 6
1507 },
1508 {
1509 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001510 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001511 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 .name = "Side Playback Volume",
1513 .info = wm_vol_info,
1514 .get = wm_vol_get,
1515 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001516 .private_value = (2 << 8) | 6,
1517 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 }
1519};
1520
Bill Pembertone23e7a12012-12-06 12:35:10 -05001521static struct snd_kcontrol_new wm_controls[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001522 {
1523 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 .name = "PCM Playback Switch",
1525 .info = wm_pcm_mute_info,
1526 .get = wm_pcm_mute_get,
1527 .put = wm_pcm_mute_put
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001528 },
1529 {
1530 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001531 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001532 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 .name = "PCM Playback Volume",
1534 .info = wm_pcm_vol_info,
1535 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001536 .put = wm_pcm_vol_put,
1537 .tlv = { .p = db_scale_wm_pcm }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001538 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 {
1540 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1541 .name = "Capture Switch",
1542 .info = wm_adc_mute_info,
1543 .get = wm_adc_mute_get,
1544 .put = wm_adc_mute_put,
1545 },
1546 {
1547 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001548 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001549 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 .name = "Capture Volume",
1551 .info = wm_adc_vol_info,
1552 .get = wm_adc_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001553 .put = wm_adc_vol_put,
1554 .tlv = { .p = db_scale_wm_adc }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 },
1556 {
1557 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1558 .name = "Capture Source",
1559 .info = wm_adc_mux_info,
1560 .get = wm_adc_mux_get,
1561 .put = wm_adc_mux_put,
1562 .private_value = 5
1563 },
1564 {
1565 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1566 .name = "External Amplifier",
1567 .info = aureon_hpamp_info,
1568 .get = aureon_hpamp_get,
1569 .put = aureon_hpamp_put
1570 },
1571 {
1572 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1573 .name = "DAC Deemphasis Switch",
1574 .info = aureon_deemp_info,
1575 .get = aureon_deemp_get,
1576 .put = aureon_deemp_put
1577 },
1578 {
1579 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1580 .name = "ADC Oversampling",
1581 .info = aureon_oversampling_info,
1582 .get = aureon_oversampling_get,
1583 .put = aureon_oversampling_put
1584 }
1585};
1586
Bill Pembertone23e7a12012-12-06 12:35:10 -05001587static struct snd_kcontrol_new ac97_controls[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001588 {
1589 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 .name = "AC97 Playback Switch",
1591 .info = aureon_ac97_mmute_info,
1592 .get = aureon_ac97_mmute_get,
1593 .put = aureon_ac97_mmute_put,
1594 .private_value = AC97_MASTER
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001595 },
1596 {
1597 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001598 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001599 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1600 .name = "AC97 Playback Volume",
1601 .info = aureon_ac97_vol_info,
1602 .get = aureon_ac97_vol_get,
1603 .put = aureon_ac97_vol_put,
1604 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001605 .tlv = { .p = db_scale_ac97_master }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001606 },
1607 {
1608 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1609 .name = "CD Playback Switch",
1610 .info = aureon_ac97_mute_info,
1611 .get = aureon_ac97_mute_get,
1612 .put = aureon_ac97_mute_put,
1613 .private_value = AC97_CD
1614 },
1615 {
1616 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001617 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001618 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1619 .name = "CD Playback Volume",
1620 .info = aureon_ac97_vol_info,
1621 .get = aureon_ac97_vol_get,
1622 .put = aureon_ac97_vol_put,
1623 .private_value = AC97_CD|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001624 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001625 },
1626 {
1627 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1628 .name = "Aux Playback Switch",
1629 .info = aureon_ac97_mute_info,
1630 .get = aureon_ac97_mute_get,
1631 .put = aureon_ac97_mute_put,
1632 .private_value = AC97_AUX,
1633 },
1634 {
1635 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001636 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001637 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1638 .name = "Aux Playback Volume",
1639 .info = aureon_ac97_vol_info,
1640 .get = aureon_ac97_vol_get,
1641 .put = aureon_ac97_vol_put,
1642 .private_value = AC97_AUX|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001643 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001644 },
1645 {
1646 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1647 .name = "Line Playback Switch",
1648 .info = aureon_ac97_mute_info,
1649 .get = aureon_ac97_mute_get,
1650 .put = aureon_ac97_mute_put,
1651 .private_value = AC97_LINE
1652 },
1653 {
1654 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001655 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001656 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1657 .name = "Line Playback Volume",
1658 .info = aureon_ac97_vol_info,
1659 .get = aureon_ac97_vol_get,
1660 .put = aureon_ac97_vol_put,
1661 .private_value = AC97_LINE|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001662 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001663 },
1664 {
1665 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1666 .name = "Mic Playback Switch",
1667 .info = aureon_ac97_mute_info,
1668 .get = aureon_ac97_mute_get,
1669 .put = aureon_ac97_mute_put,
1670 .private_value = AC97_MIC
1671 },
1672 {
1673 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001674 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001675 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1676 .name = "Mic Playback Volume",
1677 .info = aureon_ac97_vol_info,
1678 .get = aureon_ac97_vol_get,
1679 .put = aureon_ac97_vol_put,
1680 .private_value = AC97_MIC,
Takashi Iwaif640c322006-08-30 16:57:37 +02001681 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001682 },
1683 {
1684 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1685 .name = "Mic Boost (+20dB)",
1686 .info = aureon_ac97_micboost_info,
1687 .get = aureon_ac97_micboost_get,
1688 .put = aureon_ac97_micboost_put
1689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690};
1691
Bill Pembertone23e7a12012-12-06 12:35:10 -05001692static struct snd_kcontrol_new universe_ac97_controls[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001693 {
1694 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 .name = "AC97 Playback Switch",
1696 .info = aureon_ac97_mmute_info,
1697 .get = aureon_ac97_mmute_get,
1698 .put = aureon_ac97_mmute_put,
1699 .private_value = AC97_MASTER
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001700 },
1701 {
1702 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001703 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001704 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1705 .name = "AC97 Playback Volume",
1706 .info = aureon_ac97_vol_info,
1707 .get = aureon_ac97_vol_get,
1708 .put = aureon_ac97_vol_put,
1709 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001710 .tlv = { .p = db_scale_ac97_master }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001711 },
1712 {
1713 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1714 .name = "CD Playback Switch",
1715 .info = aureon_ac97_mute_info,
1716 .get = aureon_ac97_mute_get,
1717 .put = aureon_ac97_mute_put,
1718 .private_value = AC97_AUX
1719 },
1720 {
1721 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001722 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001723 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1724 .name = "CD Playback Volume",
1725 .info = aureon_ac97_vol_info,
1726 .get = aureon_ac97_vol_get,
1727 .put = aureon_ac97_vol_put,
1728 .private_value = AC97_AUX|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001729 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001730 },
1731 {
1732 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1733 .name = "Phono Playback Switch",
1734 .info = aureon_ac97_mute_info,
1735 .get = aureon_ac97_mute_get,
1736 .put = aureon_ac97_mute_put,
1737 .private_value = AC97_CD
1738 },
1739 {
1740 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001741 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001742 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1743 .name = "Phono Playback Volume",
1744 .info = aureon_ac97_vol_info,
1745 .get = aureon_ac97_vol_get,
1746 .put = aureon_ac97_vol_put,
1747 .private_value = AC97_CD|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001748 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001749 },
1750 {
1751 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1752 .name = "Line Playback Switch",
1753 .info = aureon_ac97_mute_info,
1754 .get = aureon_ac97_mute_get,
1755 .put = aureon_ac97_mute_put,
1756 .private_value = AC97_LINE
1757 },
1758 {
1759 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001760 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001761 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1762 .name = "Line Playback Volume",
1763 .info = aureon_ac97_vol_info,
1764 .get = aureon_ac97_vol_get,
1765 .put = aureon_ac97_vol_put,
1766 .private_value = AC97_LINE|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001767 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001768 },
1769 {
1770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1771 .name = "Mic Playback Switch",
1772 .info = aureon_ac97_mute_info,
1773 .get = aureon_ac97_mute_get,
1774 .put = aureon_ac97_mute_put,
1775 .private_value = AC97_MIC
1776 },
1777 {
1778 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001779 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001780 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1781 .name = "Mic Playback Volume",
1782 .info = aureon_ac97_vol_info,
1783 .get = aureon_ac97_vol_get,
1784 .put = aureon_ac97_vol_put,
1785 .private_value = AC97_MIC,
Takashi Iwaif640c322006-08-30 16:57:37 +02001786 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001787 },
1788 {
1789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1790 .name = "Mic Boost (+20dB)",
1791 .info = aureon_ac97_micboost_info,
1792 .get = aureon_ac97_micboost_get,
1793 .put = aureon_ac97_micboost_put
1794 },
1795 {
1796 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1797 .name = "Aux Playback Switch",
1798 .info = aureon_ac97_mute_info,
1799 .get = aureon_ac97_mute_get,
1800 .put = aureon_ac97_mute_put,
1801 .private_value = AC97_VIDEO,
1802 },
1803 {
1804 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001805 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001806 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1807 .name = "Aux Playback Volume",
1808 .info = aureon_ac97_vol_info,
1809 .get = aureon_ac97_vol_get,
1810 .put = aureon_ac97_vol_put,
1811 .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001812 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001813 },
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001814 {
1815 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1816 .name = "Aux Source",
1817 .info = aureon_universe_inmux_info,
1818 .get = aureon_universe_inmux_get,
1819 .put = aureon_universe_inmux_put
1820 }
1821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822};
1823
Bill Pembertone23e7a12012-12-06 12:35:10 -05001824static struct snd_kcontrol_new cs8415_controls[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 {
1826 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001827 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 .info = aureon_cs8415_mute_info,
1829 .get = aureon_cs8415_mute_get,
1830 .put = aureon_cs8415_mute_put
1831 },
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001832 {
1833 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1834 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Source",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 .info = aureon_cs8415_mux_info,
1836 .get = aureon_cs8415_mux_get,
1837 .put = aureon_cs8415_mux_put,
1838 },
1839 {
1840 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001841 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ", CAPTURE, DEFAULT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1843 .info = aureon_cs8415_qsub_info,
1844 .get = aureon_cs8415_qsub_get,
1845 },
1846 {
1847 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001848 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1850 .info = aureon_cs8415_spdif_info,
1851 .get = aureon_cs8415_mask_get
1852 },
1853 {
1854 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001855 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1857 .info = aureon_cs8415_spdif_info,
1858 .get = aureon_cs8415_spdif_get
1859 },
1860 {
1861 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001862 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Rate",
1863 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 .info = aureon_cs8415_rate_info,
1865 .get = aureon_cs8415_rate_get
1866 }
1867};
1868
Bill Pembertone23e7a12012-12-06 12:35:10 -05001869static int aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870{
1871 unsigned int i, counts;
1872 int err;
1873
1874 counts = ARRAY_SIZE(aureon_dac_controls);
1875 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1876 counts -= 2; /* no side */
1877 for (i = 0; i < counts; i++) {
1878 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1879 if (err < 0)
1880 return err;
1881 }
1882
1883 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1884 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1885 if (err < 0)
1886 return err;
1887 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001888
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1890 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1891 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1892 if (err < 0)
1893 return err;
1894 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001895 } else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001896 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1898 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1899 if (err < 0)
1900 return err;
1901 }
1902 }
1903
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001904 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1905 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 unsigned char id;
1907 snd_ice1712_save_gpio_status(ice);
1908 id = aureon_cs8415_get(ice, CS8415_ID);
1909 if (id != 0x41)
Takashi Iwai6dfb5af2014-02-25 17:16:16 +01001910 dev_info(ice->card->dev,
1911 "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 else if ((id & 0x0F) != 0x01)
Takashi Iwai6dfb5af2014-02-25 17:16:16 +01001913 dev_info(ice->card->dev,
1914 "Detected unsupported CS8415 rev. (%c)\n",
1915 (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 else {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001917 for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001918 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1920 if (err < 0)
1921 return err;
1922 if (i > 1)
1923 kctl->id.device = ice->pcm->device;
1924 }
1925 }
1926 snd_ice1712_restore_gpio_status(ice);
1927 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 return 0;
1930}
1931
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932/*
Bernhard Urbanae761482010-03-23 04:12:38 +01001933 * reset the chip
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 */
Bernhard Urbanae761482010-03-23 04:12:38 +01001935static int aureon_reset(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001937 static const unsigned short wm_inits_aureon[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 /* These come first to reduce init pop noise */
1939 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1940 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1941 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1942
1943 0x18, 0x000, /* All power-up */
1944
1945 0x16, 0x122, /* I2S, normal polarity, 24bit */
1946 0x17, 0x022, /* 256fs, slave mode */
1947 0x00, 0, /* DAC1 analog mute */
1948 0x01, 0, /* DAC2 analog mute */
1949 0x02, 0, /* DAC3 analog mute */
1950 0x03, 0, /* DAC4 analog mute */
1951 0x04, 0, /* DAC5 analog mute */
1952 0x05, 0, /* DAC6 analog mute */
1953 0x06, 0, /* DAC7 analog mute */
1954 0x07, 0, /* DAC8 analog mute */
1955 0x08, 0x100, /* master analog mute */
1956 0x09, 0xff, /* DAC1 digital full */
1957 0x0a, 0xff, /* DAC2 digital full */
1958 0x0b, 0xff, /* DAC3 digital full */
1959 0x0c, 0xff, /* DAC4 digital full */
1960 0x0d, 0xff, /* DAC5 digital full */
1961 0x0e, 0xff, /* DAC6 digital full */
1962 0x0f, 0xff, /* DAC7 digital full */
1963 0x10, 0xff, /* DAC8 digital full */
1964 0x11, 0x1ff, /* master digital full */
1965 0x12, 0x000, /* phase normal */
1966 0x13, 0x090, /* unmute DAC L/R */
1967 0x14, 0x000, /* all unmute */
1968 0x15, 0x000, /* no deemphasis, no ZFLG */
1969 0x19, 0x000, /* -12dB ADC/L */
1970 0x1a, 0x000, /* -12dB ADC/R */
1971 (unsigned short)-1
1972 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001973 static const unsigned short wm_inits_prodigy[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974
1975 /* These come first to reduce init pop noise */
1976 0x1b, 0x000, /* ADC Mux */
1977 0x1c, 0x009, /* Out Mux1 */
1978 0x1d, 0x009, /* Out Mux2 */
1979
1980 0x18, 0x000, /* All power-up */
1981
1982 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
1983 0x17, 0x006, /* 128fs, slave mode */
1984
1985 0x00, 0, /* DAC1 analog mute */
1986 0x01, 0, /* DAC2 analog mute */
1987 0x02, 0, /* DAC3 analog mute */
1988 0x03, 0, /* DAC4 analog mute */
1989 0x04, 0, /* DAC5 analog mute */
1990 0x05, 0, /* DAC6 analog mute */
1991 0x06, 0, /* DAC7 analog mute */
1992 0x07, 0, /* DAC8 analog mute */
1993 0x08, 0x100, /* master analog mute */
1994
1995 0x09, 0x7f, /* DAC1 digital full */
1996 0x0a, 0x7f, /* DAC2 digital full */
1997 0x0b, 0x7f, /* DAC3 digital full */
1998 0x0c, 0x7f, /* DAC4 digital full */
1999 0x0d, 0x7f, /* DAC5 digital full */
2000 0x0e, 0x7f, /* DAC6 digital full */
2001 0x0f, 0x7f, /* DAC7 digital full */
2002 0x10, 0x7f, /* DAC8 digital full */
2003 0x11, 0x1FF, /* master digital full */
2004
2005 0x12, 0x000, /* phase normal */
2006 0x13, 0x090, /* unmute DAC L/R */
2007 0x14, 0x000, /* all unmute */
2008 0x15, 0x000, /* no deemphasis, no ZFLG */
2009
2010 0x19, 0x000, /* -12dB ADC/L */
2011 0x1a, 0x000, /* -12dB ADC/R */
2012 (unsigned short)-1
2013
2014 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01002015 static const unsigned short cs_inits[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 0x0441, /* RUN */
2017 0x0180, /* no mute, OMCK output on RMCK pin */
2018 0x0201, /* S/PDIF source on RXP1 */
2019 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
2020 (unsigned short)-1
2021 };
2022 unsigned int tmp;
Takashi Iwai32b47da2007-01-29 15:26:36 +01002023 const unsigned short *p;
Bernhard Urbanae761482010-03-23 04:12:38 +01002024 int err;
2025 struct aureon_spec *spec = ice->spec;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002026
2027 err = aureon_ac97_init(ice);
2028 if (err != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 return err;
2030
2031 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
2032
2033 /* reset the wm codec as the SPI mode */
2034 snd_ice1712_save_gpio_status(ice);
2035 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
2036
2037 tmp = snd_ice1712_gpio_read(ice);
2038 tmp &= ~AUREON_WM_RESET;
2039 snd_ice1712_gpio_write(ice, tmp);
2040 udelay(1);
2041 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
2042 snd_ice1712_gpio_write(ice, tmp);
2043 udelay(1);
2044 tmp |= AUREON_WM_RESET;
2045 snd_ice1712_gpio_write(ice, tmp);
2046 udelay(1);
2047
2048 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002049 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002050 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002051 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 p = wm_inits_prodigy;
2053 else
2054 p = wm_inits_aureon;
2055 for (; *p != (unsigned short)-1; p += 2)
2056 wm_put(ice, p[0], p[1]);
2057
2058 /* initialize CS8415A codec */
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002059 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
2060 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +01002061 for (p = cs_inits; *p != (unsigned short)-1; p++)
2062 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002063 spec->cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064
Takashi Iwai45fe7222006-01-13 13:50:16 +01002065 aureon_set_headphone_amp(ice, 1);
2066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
2068 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002069
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002070 /* initialize PCA9554 pin directions & set default input */
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002071 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2072 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Bernhard Urbanae761482010-03-23 04:12:38 +01002073 return 0;
2074}
2075
2076/*
2077 * suspend/resume
2078 */
Takashi Iwaic7561cd2012-08-14 18:12:04 +02002079#ifdef CONFIG_PM_SLEEP
Bernhard Urbanae761482010-03-23 04:12:38 +01002080static int aureon_resume(struct snd_ice1712 *ice)
2081{
2082 struct aureon_spec *spec = ice->spec;
2083 int err, i;
2084
2085 err = aureon_reset(ice);
2086 if (err != 0)
2087 return err;
2088
2089 /* workaround for poking volume with alsamixer after resume:
2090 * just set stored volume again */
2091 for (i = 0; i < ice->num_total_dacs; i++)
2092 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
2093 return 0;
2094}
2095#endif
2096
2097/*
2098 * initialize the chip
2099 */
Bill Pembertone23e7a12012-12-06 12:35:10 -05002100static int aureon_init(struct snd_ice1712 *ice)
Bernhard Urbanae761482010-03-23 04:12:38 +01002101{
2102 struct aureon_spec *spec;
2103 int i, err;
2104
2105 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2106 if (!spec)
2107 return -ENOMEM;
2108 ice->spec = spec;
2109
2110 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
2111 ice->num_total_dacs = 6;
2112 ice->num_total_adcs = 2;
2113 } else {
2114 /* aureon 7.1 and prodigy 7.1 */
2115 ice->num_total_dacs = 8;
2116 ice->num_total_adcs = 2;
2117 }
2118
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002119 /* to remember the register values of CS8415 */
Bernhard Urbanae761482010-03-23 04:12:38 +01002120 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
2121 if (!ice->akm)
2122 return -ENOMEM;
2123 ice->akm_codecs = 1;
2124
2125 err = aureon_reset(ice);
2126 if (err != 0)
2127 return err;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002128
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002129 spec->master[0] = WM_VOL_MUTE;
2130 spec->master[1] = WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 for (i = 0; i < ice->num_total_dacs; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002132 spec->vol[i] = WM_VOL_MUTE;
2133 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 }
2135
Takashi Iwaic7561cd2012-08-14 18:12:04 +02002136#ifdef CONFIG_PM_SLEEP
Bernhard Urbanae761482010-03-23 04:12:38 +01002137 ice->pm_resume = aureon_resume;
2138 ice->pm_suspend_enabled = 1;
2139#endif
2140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 return 0;
2142}
2143
2144
2145/*
2146 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2147 * hence the driver needs to sets up it properly.
2148 */
2149
Bill Pembertone23e7a12012-12-06 12:35:10 -05002150static unsigned char aureon51_eeprom[] = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002151 [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
2152 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2153 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2154 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2155 [ICE_EEP2_GPIO_DIR] = 0xff,
2156 [ICE_EEP2_GPIO_DIR1] = 0xff,
2157 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2158 [ICE_EEP2_GPIO_MASK] = 0x00,
2159 [ICE_EEP2_GPIO_MASK1] = 0x00,
2160 [ICE_EEP2_GPIO_MASK2] = 0x00,
2161 [ICE_EEP2_GPIO_STATE] = 0x00,
2162 [ICE_EEP2_GPIO_STATE1] = 0x00,
2163 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164};
2165
Bill Pembertone23e7a12012-12-06 12:35:10 -05002166static unsigned char aureon71_eeprom[] = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002167 [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
2168 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2169 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2170 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2171 [ICE_EEP2_GPIO_DIR] = 0xff,
2172 [ICE_EEP2_GPIO_DIR1] = 0xff,
2173 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2174 [ICE_EEP2_GPIO_MASK] = 0x00,
2175 [ICE_EEP2_GPIO_MASK1] = 0x00,
2176 [ICE_EEP2_GPIO_MASK2] = 0x00,
2177 [ICE_EEP2_GPIO_STATE] = 0x00,
2178 [ICE_EEP2_GPIO_STATE1] = 0x00,
2179 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180};
Takashi Iwai189bc172007-01-29 15:25:40 +01002181#define prodigy71_eeprom aureon71_eeprom
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
Bill Pembertone23e7a12012-12-06 12:35:10 -05002183static unsigned char aureon71_universe_eeprom[] = {
Maximilian Rehkopfc1805dd2008-08-29 14:11:10 +02002184 [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC,
2185 * 4DACs
2186 */
2187 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2188 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2189 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2190 [ICE_EEP2_GPIO_DIR] = 0xff,
2191 [ICE_EEP2_GPIO_DIR1] = 0xff,
2192 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2193 [ICE_EEP2_GPIO_MASK] = 0x00,
2194 [ICE_EEP2_GPIO_MASK1] = 0x00,
2195 [ICE_EEP2_GPIO_MASK2] = 0x00,
2196 [ICE_EEP2_GPIO_STATE] = 0x00,
2197 [ICE_EEP2_GPIO_STATE1] = 0x00,
2198 [ICE_EEP2_GPIO_STATE2] = 0x00,
2199};
2200
Bill Pembertone23e7a12012-12-06 12:35:10 -05002201static unsigned char prodigy71lt_eeprom[] = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002202 [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
2203 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2204 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2205 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2206 [ICE_EEP2_GPIO_DIR] = 0xff,
2207 [ICE_EEP2_GPIO_DIR1] = 0xff,
2208 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2209 [ICE_EEP2_GPIO_MASK] = 0x00,
2210 [ICE_EEP2_GPIO_MASK1] = 0x00,
2211 [ICE_EEP2_GPIO_MASK2] = 0x00,
2212 [ICE_EEP2_GPIO_STATE] = 0x00,
2213 [ICE_EEP2_GPIO_STATE1] = 0x00,
2214 [ICE_EEP2_GPIO_STATE2] = 0x00,
Takashi Iwai45fe7222006-01-13 13:50:16 +01002215};
Takashi Iwai189bc172007-01-29 15:25:40 +01002216#define prodigy71xt_eeprom prodigy71lt_eeprom
Takashi Iwai45fe7222006-01-13 13:50:16 +01002217
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218/* entry point */
Bill Pembertone23e7a12012-12-06 12:35:10 -05002219struct snd_ice1712_card_info snd_vt1724_aureon_cards[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 {
2221 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2222 .name = "Terratec Aureon 5.1-Sky",
2223 .model = "aureon51",
2224 .chip_init = aureon_init,
2225 .build_controls = aureon_add_controls,
2226 .eeprom_size = sizeof(aureon51_eeprom),
2227 .eeprom_data = aureon51_eeprom,
2228 .driver = "Aureon51",
2229 },
2230 {
2231 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2232 .name = "Terratec Aureon 7.1-Space",
2233 .model = "aureon71",
2234 .chip_init = aureon_init,
2235 .build_controls = aureon_add_controls,
2236 .eeprom_size = sizeof(aureon71_eeprom),
2237 .eeprom_data = aureon71_eeprom,
2238 .driver = "Aureon71",
2239 },
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002240 {
2241 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2242 .name = "Terratec Aureon 7.1-Universe",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 .model = "universe",
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002244 .chip_init = aureon_init,
2245 .build_controls = aureon_add_controls,
Maximilian Rehkopfc1805dd2008-08-29 14:11:10 +02002246 .eeprom_size = sizeof(aureon71_universe_eeprom),
2247 .eeprom_data = aureon71_universe_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002248 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 },
2250 {
2251 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2252 .name = "Audiotrak Prodigy 7.1",
2253 .model = "prodigy71",
2254 .chip_init = aureon_init,
2255 .build_controls = aureon_add_controls,
2256 .eeprom_size = sizeof(prodigy71_eeprom),
2257 .eeprom_data = prodigy71_eeprom,
2258 .driver = "Prodigy71", /* should be identical with Aureon71 */
2259 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002260 {
2261 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2262 .name = "Audiotrak Prodigy 7.1 LT",
2263 .model = "prodigy71lt",
2264 .chip_init = aureon_init,
2265 .build_controls = aureon_add_controls,
2266 .eeprom_size = sizeof(prodigy71lt_eeprom),
2267 .eeprom_data = prodigy71lt_eeprom,
2268 .driver = "Prodigy71LT",
2269 },
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002270 {
2271 .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
2272 .name = "Audiotrak Prodigy 7.1 XT",
2273 .model = "prodigy71xt",
2274 .chip_init = aureon_init,
2275 .build_controls = aureon_add_controls,
2276 .eeprom_size = sizeof(prodigy71xt_eeprom),
2277 .eeprom_data = prodigy71xt_eeprom,
2278 .driver = "Prodigy71LT",
2279 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 { } /* terminator */
2281};