blob: 4f9657084603897c868802b268a32c57dcb6c7b1 [file] [log] [blame]
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001/*
2 * card driver for models with WM8776/WM8766 DACs (Xonar DS)
3 *
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 *
6 *
7 * This driver is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 2.
9 *
10 * This driver is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this driver; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Xonar DS
21 * --------
22 *
23 * CMI8788:
24 *
Clemens Ladischde664932010-12-02 11:42:48 +010025 * SPI 0 -> WM8766 (surround, center/LFE, back)
26 * SPI 1 -> WM8776 (front, input)
Clemens Ladischd1db38c2010-01-18 15:44:04 +010027 *
Clemens Ladischde664932010-12-02 11:42:48 +010028 * GPIO 4 <- headphone detect, 0 = plugged
29 * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
30 * GPIO 7 -> enable output to front L/R speaker channels
31 * GPIO 8 -> enable output to other speaker channels and front panel headphone
Clemens Ladisch9bac84e2010-09-09 12:19:21 +020032 *
Clemens Ladischde664932010-12-02 11:42:48 +010033 * WM8776:
Clemens Ladisch9bac84e2010-09-09 12:19:21 +020034 *
Clemens Ladischde664932010-12-02 11:42:48 +010035 * input 1 <- line
36 * input 2 <- mic
37 * input 3 <- front mic
38 * input 4 <- aux
39 */
40
41/*
42 * Xonar HDAV1.3 Slim
43 * ------------------
44 *
45 * CMI8788:
46 *
47 * I²C <-> WM8776 (addr 0011010)
48 *
49 * GPIO 0 -> disable HDMI output
50 * GPIO 1 -> enable HP output
51 * GPIO 6 -> firmware EEPROM I²C clock
52 * GPIO 7 <-> firmware EEPROM I²C data
53 *
54 * UART <-> HDMI controller
55 *
56 * WM8776:
57 *
58 * input 1 <- mic
59 * input 2 <- aux
Clemens Ladischd1db38c2010-01-18 15:44:04 +010060 */
61
62#include <linux/pci.h>
63#include <linux/delay.h>
64#include <sound/control.h>
65#include <sound/core.h>
Clemens Ladisch9719fca2010-12-02 11:41:10 +010066#include <sound/info.h>
Clemens Ladisch435feac2010-09-09 12:20:29 +020067#include <sound/jack.h>
Clemens Ladischd1db38c2010-01-18 15:44:04 +010068#include <sound/pcm.h>
69#include <sound/pcm_params.h>
70#include <sound/tlv.h>
71#include "xonar.h"
72#include "wm8776.h"
73#include "wm8766.h"
74
75#define GPIO_DS_HP_DETECT 0x0010
76#define GPIO_DS_INPUT_ROUTE 0x0040
Clemens Ladisch84cf83a2010-09-09 12:23:06 +020077#define GPIO_DS_OUTPUT_FRONTLR 0x0080
78#define GPIO_DS_OUTPUT_ENABLE 0x0100
Clemens Ladischd1db38c2010-01-18 15:44:04 +010079
80#define LC_CONTROL_LIMITER 0x40000000
81#define LC_CONTROL_ALC 0x20000000
82
83struct xonar_wm87x6 {
84 struct xonar_generic generic;
85 u16 wm8776_regs[0x17];
86 u16 wm8766_regs[0x10];
Clemens Ladischfe6ce802010-09-07 13:38:49 +020087 struct snd_kcontrol *line_adcmux_control;
88 struct snd_kcontrol *mic_adcmux_control;
Clemens Ladischd1db38c2010-01-18 15:44:04 +010089 struct snd_kcontrol *lc_controls[13];
Clemens Ladisch435feac2010-09-09 12:20:29 +020090 struct snd_jack *hp_jack;
Clemens Ladischd1db38c2010-01-18 15:44:04 +010091};
92
93static void wm8776_write(struct oxygen *chip,
94 unsigned int reg, unsigned int value)
95{
96 struct xonar_wm87x6 *data = chip->model_data;
97
98 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
99 OXYGEN_SPI_DATA_LENGTH_2 |
100 OXYGEN_SPI_CLOCK_160 |
101 (1 << OXYGEN_SPI_CODEC_SHIFT) |
102 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
103 (reg << 9) | value);
104 if (reg < ARRAY_SIZE(data->wm8776_regs)) {
Clemens Ladischfaf4eb22010-03-03 09:16:18 +0100105 if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER)
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100106 value &= ~WM8776_UPDATE;
107 data->wm8776_regs[reg] = value;
108 }
109}
110
111static void wm8776_write_cached(struct oxygen *chip,
112 unsigned int reg, unsigned int value)
113{
114 struct xonar_wm87x6 *data = chip->model_data;
115
116 if (reg >= ARRAY_SIZE(data->wm8776_regs) ||
117 value != data->wm8776_regs[reg])
118 wm8776_write(chip, reg, value);
119}
120
121static void wm8766_write(struct oxygen *chip,
122 unsigned int reg, unsigned int value)
123{
124 struct xonar_wm87x6 *data = chip->model_data;
125
126 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
127 OXYGEN_SPI_DATA_LENGTH_2 |
128 OXYGEN_SPI_CLOCK_160 |
129 (0 << OXYGEN_SPI_CODEC_SHIFT) |
130 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
131 (reg << 9) | value);
Clemens Ladischda0dab52010-09-09 12:18:35 +0200132 if (reg < ARRAY_SIZE(data->wm8766_regs)) {
133 if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
134 (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
135 value &= ~WM8766_UPDATE;
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100136 data->wm8766_regs[reg] = value;
Clemens Ladischda0dab52010-09-09 12:18:35 +0200137 }
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100138}
139
140static void wm8766_write_cached(struct oxygen *chip,
141 unsigned int reg, unsigned int value)
142{
143 struct xonar_wm87x6 *data = chip->model_data;
144
145 if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
Clemens Ladischda0dab52010-09-09 12:18:35 +0200146 value != data->wm8766_regs[reg])
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100147 wm8766_write(chip, reg, value);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100148}
149
150static void wm8776_registers_init(struct oxygen *chip)
151{
152 struct xonar_wm87x6 *data = chip->model_data;
153
154 wm8776_write(chip, WM8776_RESET, 0);
155 wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN |
156 WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT);
157 wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0);
158 wm8776_write(chip, WM8776_DACIFCTRL,
159 WM8776_DACFMT_LJUST | WM8776_DACWL_24);
160 wm8776_write(chip, WM8776_ADCIFCTRL,
161 data->wm8776_regs[WM8776_ADCIFCTRL]);
162 wm8776_write(chip, WM8776_MSTRCTRL, data->wm8776_regs[WM8776_MSTRCTRL]);
163 wm8776_write(chip, WM8776_PWRDOWN, data->wm8776_regs[WM8776_PWRDOWN]);
164 wm8776_write(chip, WM8776_HPLVOL, data->wm8776_regs[WM8776_HPLVOL]);
165 wm8776_write(chip, WM8776_HPRVOL, data->wm8776_regs[WM8776_HPRVOL] |
166 WM8776_UPDATE);
167 wm8776_write(chip, WM8776_ADCLVOL, data->wm8776_regs[WM8776_ADCLVOL]);
168 wm8776_write(chip, WM8776_ADCRVOL, data->wm8776_regs[WM8776_ADCRVOL]);
169 wm8776_write(chip, WM8776_ADCMUX, data->wm8776_regs[WM8776_ADCMUX]);
170 wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0]);
171 wm8776_write(chip, WM8776_DACRVOL, chip->dac_volume[1] | WM8776_UPDATE);
172}
173
174static void wm8766_registers_init(struct oxygen *chip)
175{
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200176 struct xonar_wm87x6 *data = chip->model_data;
177
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100178 wm8766_write(chip, WM8766_RESET, 0);
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200179 wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100180 wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
181 wm8766_write(chip, WM8766_DAC_CTRL2,
182 WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
183 wm8766_write(chip, WM8766_LDA1, chip->dac_volume[2]);
184 wm8766_write(chip, WM8766_RDA1, chip->dac_volume[3]);
185 wm8766_write(chip, WM8766_LDA2, chip->dac_volume[4]);
186 wm8766_write(chip, WM8766_RDA2, chip->dac_volume[5]);
187 wm8766_write(chip, WM8766_LDA3, chip->dac_volume[6]);
188 wm8766_write(chip, WM8766_RDA3, chip->dac_volume[7] | WM8766_UPDATE);
189}
190
191static void wm8776_init(struct oxygen *chip)
192{
193 struct xonar_wm87x6 *data = chip->model_data;
194
195 data->wm8776_regs[WM8776_HPLVOL] = (0x79 - 60) | WM8776_HPZCEN;
196 data->wm8776_regs[WM8776_HPRVOL] = (0x79 - 60) | WM8776_HPZCEN;
197 data->wm8776_regs[WM8776_ADCIFCTRL] =
198 WM8776_ADCFMT_LJUST | WM8776_ADCWL_24 | WM8776_ADCMCLK;
199 data->wm8776_regs[WM8776_MSTRCTRL] =
200 WM8776_ADCRATE_256 | WM8776_DACRATE_256;
201 data->wm8776_regs[WM8776_PWRDOWN] = WM8776_HPPD;
202 data->wm8776_regs[WM8776_ADCLVOL] = 0xa5 | WM8776_ZCA;
203 data->wm8776_regs[WM8776_ADCRVOL] = 0xa5 | WM8776_ZCA;
204 data->wm8776_regs[WM8776_ADCMUX] = 0x001;
205 wm8776_registers_init(chip);
206}
207
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200208static void wm8766_init(struct oxygen *chip)
Clemens Ladisch435feac2010-09-09 12:20:29 +0200209{
210 struct xonar_wm87x6 *data = chip->model_data;
Clemens Ladisch435feac2010-09-09 12:20:29 +0200211
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200212 data->wm8766_regs[WM8766_DAC_CTRL] =
213 WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
214 wm8766_registers_init(chip);
215}
216
217static void xonar_ds_handle_hp_jack(struct oxygen *chip)
218{
219 struct xonar_wm87x6 *data = chip->model_data;
220 bool hp_plugged;
221 unsigned int reg;
222
223 mutex_lock(&chip->mutex);
224
225 hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
226 GPIO_DS_HP_DETECT);
227
228 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
229 hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
230 GPIO_DS_OUTPUT_FRONTLR);
231
232 reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
233 if (hp_plugged)
234 reg |= WM8766_MUTEALL;
235 wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
236
237 snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
238
239 mutex_unlock(&chip->mutex);
Clemens Ladisch435feac2010-09-09 12:20:29 +0200240}
241
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100242static void xonar_ds_init(struct oxygen *chip)
243{
244 struct xonar_wm87x6 *data = chip->model_data;
245
246 data->generic.anti_pop_delay = 300;
247 data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
248
249 wm8776_init(chip);
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200250 wm8766_init(chip);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100251
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200252 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
253 GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
254 oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
255 GPIO_DS_HP_DETECT);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100256 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
257 oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
258 chip->interrupt_mask |= OXYGEN_INT_GPIO;
259
260 xonar_enable_output(chip);
261
Clemens Ladisch435feac2010-09-09 12:20:29 +0200262 snd_jack_new(chip->card, "Headphone",
263 SND_JACK_HEADPHONE, &data->hp_jack);
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200264 xonar_ds_handle_hp_jack(chip);
Clemens Ladisch435feac2010-09-09 12:20:29 +0200265
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100266 snd_component_add(chip->card, "WM8776");
267 snd_component_add(chip->card, "WM8766");
268}
269
270static void xonar_ds_cleanup(struct oxygen *chip)
271{
272 xonar_disable_output(chip);
Clemens Ladisch4c25b932010-09-07 13:37:10 +0200273 wm8776_write(chip, WM8776_RESET, 0);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100274}
275
276static void xonar_ds_suspend(struct oxygen *chip)
277{
278 xonar_ds_cleanup(chip);
279}
280
281static void xonar_ds_resume(struct oxygen *chip)
282{
283 wm8776_registers_init(chip);
284 wm8766_registers_init(chip);
285 xonar_enable_output(chip);
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200286 xonar_ds_handle_hp_jack(chip);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100287}
288
289static void wm8776_adc_hardware_filter(unsigned int channel,
290 struct snd_pcm_hardware *hardware)
291{
292 if (channel == PCM_A) {
293 hardware->rates = SNDRV_PCM_RATE_32000 |
294 SNDRV_PCM_RATE_44100 |
295 SNDRV_PCM_RATE_48000 |
296 SNDRV_PCM_RATE_64000 |
297 SNDRV_PCM_RATE_88200 |
298 SNDRV_PCM_RATE_96000;
299 hardware->rate_max = 96000;
300 }
301}
302
303static void set_wm87x6_dac_params(struct oxygen *chip,
304 struct snd_pcm_hw_params *params)
305{
306}
307
308static void set_wm8776_adc_params(struct oxygen *chip,
309 struct snd_pcm_hw_params *params)
310{
311 u16 reg;
312
313 reg = WM8776_ADCRATE_256 | WM8776_DACRATE_256;
314 if (params_rate(params) > 48000)
315 reg |= WM8776_ADCOSR;
316 wm8776_write_cached(chip, WM8776_MSTRCTRL, reg);
317}
318
319static void update_wm8776_volume(struct oxygen *chip)
320{
321 struct xonar_wm87x6 *data = chip->model_data;
322 u8 to_change;
323
324 if (chip->dac_volume[0] == chip->dac_volume[1]) {
325 if (chip->dac_volume[0] != data->wm8776_regs[WM8776_DACLVOL] ||
326 chip->dac_volume[1] != data->wm8776_regs[WM8776_DACRVOL]) {
327 wm8776_write(chip, WM8776_DACMASTER,
328 chip->dac_volume[0] | WM8776_UPDATE);
329 data->wm8776_regs[WM8776_DACLVOL] = chip->dac_volume[0];
330 data->wm8776_regs[WM8776_DACRVOL] = chip->dac_volume[0];
331 }
332 } else {
333 to_change = (chip->dac_volume[0] !=
334 data->wm8776_regs[WM8776_DACLVOL]) << 0;
335 to_change |= (chip->dac_volume[1] !=
336 data->wm8776_regs[WM8776_DACLVOL]) << 1;
337 if (to_change & 1)
338 wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0] |
339 ((to_change & 2) ? 0 : WM8776_UPDATE));
340 if (to_change & 2)
341 wm8776_write(chip, WM8776_DACRVOL,
342 chip->dac_volume[1] | WM8776_UPDATE);
343 }
344}
345
346static void update_wm87x6_volume(struct oxygen *chip)
347{
348 static const u8 wm8766_regs[6] = {
349 WM8766_LDA1, WM8766_RDA1,
350 WM8766_LDA2, WM8766_RDA2,
351 WM8766_LDA3, WM8766_RDA3,
352 };
353 struct xonar_wm87x6 *data = chip->model_data;
354 unsigned int i;
355 u8 to_change;
356
357 update_wm8776_volume(chip);
358 if (chip->dac_volume[2] == chip->dac_volume[3] &&
359 chip->dac_volume[2] == chip->dac_volume[4] &&
360 chip->dac_volume[2] == chip->dac_volume[5] &&
361 chip->dac_volume[2] == chip->dac_volume[6] &&
362 chip->dac_volume[2] == chip->dac_volume[7]) {
363 to_change = 0;
364 for (i = 0; i < 6; ++i)
365 if (chip->dac_volume[2] !=
366 data->wm8766_regs[wm8766_regs[i]])
367 to_change = 1;
368 if (to_change) {
369 wm8766_write(chip, WM8766_MASTDA,
370 chip->dac_volume[2] | WM8766_UPDATE);
371 for (i = 0; i < 6; ++i)
372 data->wm8766_regs[wm8766_regs[i]] =
373 chip->dac_volume[2];
374 }
375 } else {
376 to_change = 0;
377 for (i = 0; i < 6; ++i)
378 to_change |= (chip->dac_volume[2 + i] !=
379 data->wm8766_regs[wm8766_regs[i]]) << i;
380 for (i = 0; i < 6; ++i)
381 if (to_change & (1 << i))
382 wm8766_write(chip, wm8766_regs[i],
383 chip->dac_volume[2 + i] |
384 ((to_change & (0x3e << i))
385 ? 0 : WM8766_UPDATE));
386 }
387}
388
389static void update_wm8776_mute(struct oxygen *chip)
390{
391 wm8776_write_cached(chip, WM8776_DACMUTE,
392 chip->dac_mute ? WM8776_DMUTE : 0);
393}
394
395static void update_wm87x6_mute(struct oxygen *chip)
396{
397 update_wm8776_mute(chip);
398 wm8766_write_cached(chip, WM8766_DAC_CTRL2, WM8766_ZCD |
399 (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
400}
401
Clemens Ladisch2dbf0ea2010-09-09 12:24:35 +0200402static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
403{
404 struct xonar_wm87x6 *data = chip->model_data;
405 unsigned int reg;
406
407 /*
408 * The WM8766 can mix left and right channels, but this setting
409 * applies to all three stereo pairs.
410 */
411 reg = data->wm8766_regs[WM8766_DAC_CTRL] &
412 ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
413 if (mixed)
414 reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
415 else
416 reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
417 wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
418}
419
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100420static void xonar_ds_gpio_changed(struct oxygen *chip)
421{
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200422 xonar_ds_handle_hp_jack(chip);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100423}
424
425static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
426 struct snd_ctl_elem_value *value)
427{
428 struct oxygen *chip = ctl->private_data;
429 struct xonar_wm87x6 *data = chip->model_data;
430 u16 bit = ctl->private_value & 0xffff;
431 unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
432 bool invert = (ctl->private_value >> 24) & 1;
433
434 value->value.integer.value[0] =
435 ((data->wm8776_regs[reg_index] & bit) != 0) ^ invert;
436 return 0;
437}
438
439static int wm8776_bit_switch_put(struct snd_kcontrol *ctl,
440 struct snd_ctl_elem_value *value)
441{
442 struct oxygen *chip = ctl->private_data;
443 struct xonar_wm87x6 *data = chip->model_data;
444 u16 bit = ctl->private_value & 0xffff;
445 u16 reg_value;
446 unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
447 bool invert = (ctl->private_value >> 24) & 1;
448 int changed;
449
450 mutex_lock(&chip->mutex);
451 reg_value = data->wm8776_regs[reg_index] & ~bit;
452 if (value->value.integer.value[0] ^ invert)
453 reg_value |= bit;
454 changed = reg_value != data->wm8776_regs[reg_index];
455 if (changed)
456 wm8776_write(chip, reg_index, reg_value);
457 mutex_unlock(&chip->mutex);
458 return changed;
459}
460
461static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
462 struct snd_ctl_elem_info *info)
463{
464 static const char *const hld[16] = {
465 "0 ms", "2.67 ms", "5.33 ms", "10.6 ms",
466 "21.3 ms", "42.7 ms", "85.3 ms", "171 ms",
467 "341 ms", "683 ms", "1.37 s", "2.73 s",
468 "5.46 s", "10.9 s", "21.8 s", "43.7 s",
469 };
470 static const char *const atk_lim[11] = {
471 "0.25 ms", "0.5 ms", "1 ms", "2 ms",
472 "4 ms", "8 ms", "16 ms", "32 ms",
473 "64 ms", "128 ms", "256 ms",
474 };
475 static const char *const atk_alc[11] = {
476 "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms",
477 "134 ms", "269 ms", "538 ms", "1.08 s",
478 "2.15 s", "4.3 s", "8.6 s",
479 };
480 static const char *const dcy_lim[11] = {
481 "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms",
482 "19.2 ms", "38.4 ms", "76.8 ms", "154 ms",
483 "307 ms", "614 ms", "1.23 s",
484 };
485 static const char *const dcy_alc[11] = {
486 "33.5 ms", "67.0 ms", "134 ms", "268 ms",
487 "536 ms", "1.07 s", "2.14 s", "4.29 s",
488 "8.58 s", "17.2 s", "34.3 s",
489 };
490 static const char *const tranwin[8] = {
491 "0 us", "62.5 us", "125 us", "250 us",
492 "500 us", "1 ms", "2 ms", "4 ms",
493 };
494 u8 max;
495 const char *const *names;
496
497 max = (ctl->private_value >> 12) & 0xf;
498 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
499 info->count = 1;
500 info->value.enumerated.items = max + 1;
501 if (info->value.enumerated.item > max)
502 info->value.enumerated.item = max;
503 switch ((ctl->private_value >> 24) & 0x1f) {
504 case WM8776_ALCCTRL2:
505 names = hld;
506 break;
507 case WM8776_ALCCTRL3:
508 if (((ctl->private_value >> 20) & 0xf) == 0) {
509 if (ctl->private_value & LC_CONTROL_LIMITER)
510 names = atk_lim;
511 else
512 names = atk_alc;
513 } else {
514 if (ctl->private_value & LC_CONTROL_LIMITER)
515 names = dcy_lim;
516 else
517 names = dcy_alc;
518 }
519 break;
520 case WM8776_LIMITER:
521 names = tranwin;
522 break;
523 default:
524 return -ENXIO;
525 }
526 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
527 return 0;
528}
529
530static int wm8776_field_volume_info(struct snd_kcontrol *ctl,
531 struct snd_ctl_elem_info *info)
532{
533 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
534 info->count = 1;
535 info->value.integer.min = (ctl->private_value >> 8) & 0xf;
536 info->value.integer.max = (ctl->private_value >> 12) & 0xf;
537 return 0;
538}
539
540static void wm8776_field_set_from_ctl(struct snd_kcontrol *ctl)
541{
542 struct oxygen *chip = ctl->private_data;
543 struct xonar_wm87x6 *data = chip->model_data;
544 unsigned int value, reg_index, mode;
545 u8 min, max, shift;
546 u16 mask, reg_value;
547 bool invert;
548
549 if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
550 WM8776_LCSEL_LIMITER)
551 mode = LC_CONTROL_LIMITER;
552 else
553 mode = LC_CONTROL_ALC;
554 if (!(ctl->private_value & mode))
555 return;
556
557 value = ctl->private_value & 0xf;
558 min = (ctl->private_value >> 8) & 0xf;
559 max = (ctl->private_value >> 12) & 0xf;
560 mask = (ctl->private_value >> 16) & 0xf;
561 shift = (ctl->private_value >> 20) & 0xf;
562 reg_index = (ctl->private_value >> 24) & 0x1f;
563 invert = (ctl->private_value >> 29) & 0x1;
564
565 if (invert)
566 value = max - (value - min);
567 reg_value = data->wm8776_regs[reg_index];
568 reg_value &= ~(mask << shift);
569 reg_value |= value << shift;
570 wm8776_write_cached(chip, reg_index, reg_value);
571}
572
573static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value)
574{
575 struct oxygen *chip = ctl->private_data;
576 u8 min, max;
577 int changed;
578
579 min = (ctl->private_value >> 8) & 0xf;
580 max = (ctl->private_value >> 12) & 0xf;
581 if (value < min || value > max)
582 return -EINVAL;
583 mutex_lock(&chip->mutex);
584 changed = value != (ctl->private_value & 0xf);
585 if (changed) {
586 ctl->private_value = (ctl->private_value & ~0xf) | value;
587 wm8776_field_set_from_ctl(ctl);
588 }
589 mutex_unlock(&chip->mutex);
590 return changed;
591}
592
593static int wm8776_field_enum_get(struct snd_kcontrol *ctl,
594 struct snd_ctl_elem_value *value)
595{
596 value->value.enumerated.item[0] = ctl->private_value & 0xf;
597 return 0;
598}
599
600static int wm8776_field_volume_get(struct snd_kcontrol *ctl,
601 struct snd_ctl_elem_value *value)
602{
603 value->value.integer.value[0] = ctl->private_value & 0xf;
604 return 0;
605}
606
607static int wm8776_field_enum_put(struct snd_kcontrol *ctl,
608 struct snd_ctl_elem_value *value)
609{
610 return wm8776_field_set(ctl, value->value.enumerated.item[0]);
611}
612
613static int wm8776_field_volume_put(struct snd_kcontrol *ctl,
614 struct snd_ctl_elem_value *value)
615{
616 return wm8776_field_set(ctl, value->value.integer.value[0]);
617}
618
619static int wm8776_hp_vol_info(struct snd_kcontrol *ctl,
620 struct snd_ctl_elem_info *info)
621{
622 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
623 info->count = 2;
624 info->value.integer.min = 0x79 - 60;
625 info->value.integer.max = 0x7f;
626 return 0;
627}
628
629static int wm8776_hp_vol_get(struct snd_kcontrol *ctl,
630 struct snd_ctl_elem_value *value)
631{
632 struct oxygen *chip = ctl->private_data;
633 struct xonar_wm87x6 *data = chip->model_data;
634
635 mutex_lock(&chip->mutex);
636 value->value.integer.value[0] =
637 data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK;
638 value->value.integer.value[1] =
639 data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK;
640 mutex_unlock(&chip->mutex);
641 return 0;
642}
643
644static int wm8776_hp_vol_put(struct snd_kcontrol *ctl,
645 struct snd_ctl_elem_value *value)
646{
647 struct oxygen *chip = ctl->private_data;
648 struct xonar_wm87x6 *data = chip->model_data;
649 u8 to_update;
650
651 mutex_lock(&chip->mutex);
652 to_update = (value->value.integer.value[0] !=
653 (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK))
654 << 0;
655 to_update |= (value->value.integer.value[1] !=
656 (data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK))
657 << 1;
658 if (value->value.integer.value[0] == value->value.integer.value[1]) {
659 if (to_update) {
660 wm8776_write(chip, WM8776_HPMASTER,
661 value->value.integer.value[0] |
662 WM8776_HPZCEN | WM8776_UPDATE);
663 data->wm8776_regs[WM8776_HPLVOL] =
664 value->value.integer.value[0] | WM8776_HPZCEN;
665 data->wm8776_regs[WM8776_HPRVOL] =
666 value->value.integer.value[0] | WM8776_HPZCEN;
667 }
668 } else {
669 if (to_update & 1)
670 wm8776_write(chip, WM8776_HPLVOL,
671 value->value.integer.value[0] |
672 WM8776_HPZCEN |
673 ((to_update & 2) ? 0 : WM8776_UPDATE));
674 if (to_update & 2)
675 wm8776_write(chip, WM8776_HPRVOL,
676 value->value.integer.value[1] |
677 WM8776_HPZCEN | WM8776_UPDATE);
678 }
679 mutex_unlock(&chip->mutex);
680 return to_update != 0;
681}
682
683static int wm8776_input_mux_get(struct snd_kcontrol *ctl,
684 struct snd_ctl_elem_value *value)
685{
686 struct oxygen *chip = ctl->private_data;
687 struct xonar_wm87x6 *data = chip->model_data;
688 unsigned int mux_bit = ctl->private_value;
689
690 value->value.integer.value[0] =
691 !!(data->wm8776_regs[WM8776_ADCMUX] & mux_bit);
692 return 0;
693}
694
695static int wm8776_input_mux_put(struct snd_kcontrol *ctl,
696 struct snd_ctl_elem_value *value)
697{
698 struct oxygen *chip = ctl->private_data;
699 struct xonar_wm87x6 *data = chip->model_data;
Clemens Ladischfe6ce802010-09-07 13:38:49 +0200700 struct snd_kcontrol *other_ctl;
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100701 unsigned int mux_bit = ctl->private_value;
702 u16 reg;
703 int changed;
704
705 mutex_lock(&chip->mutex);
706 reg = data->wm8776_regs[WM8776_ADCMUX];
707 if (value->value.integer.value[0]) {
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100708 reg |= mux_bit;
Clemens Ladischfe6ce802010-09-07 13:38:49 +0200709 /* line-in and mic-in are exclusive */
710 mux_bit ^= 3;
711 if (reg & mux_bit) {
712 reg &= ~mux_bit;
713 if (mux_bit == 1)
714 other_ctl = data->line_adcmux_control;
715 else
716 other_ctl = data->mic_adcmux_control;
717 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
718 &other_ctl->id);
719 }
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100720 } else
721 reg &= ~mux_bit;
722 changed = reg != data->wm8776_regs[WM8776_ADCMUX];
723 if (changed) {
724 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
725 reg & 1 ? GPIO_DS_INPUT_ROUTE : 0,
726 GPIO_DS_INPUT_ROUTE);
727 wm8776_write(chip, WM8776_ADCMUX, reg);
728 }
729 mutex_unlock(&chip->mutex);
730 return changed;
731}
732
733static int wm8776_input_vol_info(struct snd_kcontrol *ctl,
734 struct snd_ctl_elem_info *info)
735{
736 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
737 info->count = 2;
738 info->value.integer.min = 0xa5;
739 info->value.integer.max = 0xff;
740 return 0;
741}
742
743static int wm8776_input_vol_get(struct snd_kcontrol *ctl,
744 struct snd_ctl_elem_value *value)
745{
746 struct oxygen *chip = ctl->private_data;
747 struct xonar_wm87x6 *data = chip->model_data;
748
749 mutex_lock(&chip->mutex);
750 value->value.integer.value[0] =
751 data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK;
752 value->value.integer.value[1] =
753 data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK;
754 mutex_unlock(&chip->mutex);
755 return 0;
756}
757
758static int wm8776_input_vol_put(struct snd_kcontrol *ctl,
759 struct snd_ctl_elem_value *value)
760{
761 struct oxygen *chip = ctl->private_data;
762 struct xonar_wm87x6 *data = chip->model_data;
763 int changed = 0;
764
765 mutex_lock(&chip->mutex);
766 changed = (value->value.integer.value[0] !=
767 (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) ||
768 (value->value.integer.value[1] !=
769 (data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK));
770 wm8776_write_cached(chip, WM8776_ADCLVOL,
771 value->value.integer.value[0] | WM8776_ZCA);
772 wm8776_write_cached(chip, WM8776_ADCRVOL,
773 value->value.integer.value[1] | WM8776_ZCA);
774 mutex_unlock(&chip->mutex);
775 return changed;
776}
777
778static int wm8776_level_control_info(struct snd_kcontrol *ctl,
779 struct snd_ctl_elem_info *info)
780{
781 static const char *const names[3] = {
782 "None", "Peak Limiter", "Automatic Level Control"
783 };
784 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
785 info->count = 1;
786 info->value.enumerated.items = 3;
787 if (info->value.enumerated.item >= 3)
788 info->value.enumerated.item = 2;
789 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
790 return 0;
791}
792
793static int wm8776_level_control_get(struct snd_kcontrol *ctl,
794 struct snd_ctl_elem_value *value)
795{
796 struct oxygen *chip = ctl->private_data;
797 struct xonar_wm87x6 *data = chip->model_data;
798
799 if (!(data->wm8776_regs[WM8776_ALCCTRL2] & WM8776_LCEN))
800 value->value.enumerated.item[0] = 0;
801 else if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
802 WM8776_LCSEL_LIMITER)
803 value->value.enumerated.item[0] = 1;
804 else
805 value->value.enumerated.item[0] = 2;
806 return 0;
807}
808
809static void activate_control(struct oxygen *chip,
810 struct snd_kcontrol *ctl, unsigned int mode)
811{
812 unsigned int access;
813
814 if (ctl->private_value & mode)
815 access = 0;
816 else
817 access = SNDRV_CTL_ELEM_ACCESS_INACTIVE;
818 if ((ctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) != access) {
819 ctl->vd[0].access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
820 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
821 }
822}
823
824static int wm8776_level_control_put(struct snd_kcontrol *ctl,
825 struct snd_ctl_elem_value *value)
826{
827 struct oxygen *chip = ctl->private_data;
828 struct xonar_wm87x6 *data = chip->model_data;
829 unsigned int mode = 0, i;
830 u16 ctrl1, ctrl2;
831 int changed;
832
833 if (value->value.enumerated.item[0] >= 3)
834 return -EINVAL;
835 mutex_lock(&chip->mutex);
836 changed = value->value.enumerated.item[0] != ctl->private_value;
837 if (changed) {
838 ctl->private_value = value->value.enumerated.item[0];
839 ctrl1 = data->wm8776_regs[WM8776_ALCCTRL1];
840 ctrl2 = data->wm8776_regs[WM8776_ALCCTRL2];
841 switch (value->value.enumerated.item[0]) {
842 default:
843 wm8776_write_cached(chip, WM8776_ALCCTRL2,
844 ctrl2 & ~WM8776_LCEN);
845 break;
846 case 1:
847 wm8776_write_cached(chip, WM8776_ALCCTRL1,
848 (ctrl1 & ~WM8776_LCSEL_MASK) |
849 WM8776_LCSEL_LIMITER);
850 wm8776_write_cached(chip, WM8776_ALCCTRL2,
851 ctrl2 | WM8776_LCEN);
852 mode = LC_CONTROL_LIMITER;
853 break;
854 case 2:
855 wm8776_write_cached(chip, WM8776_ALCCTRL1,
856 (ctrl1 & ~WM8776_LCSEL_MASK) |
857 WM8776_LCSEL_ALC_STEREO);
858 wm8776_write_cached(chip, WM8776_ALCCTRL2,
859 ctrl2 | WM8776_LCEN);
860 mode = LC_CONTROL_ALC;
861 break;
862 }
863 for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i)
864 activate_control(chip, data->lc_controls[i], mode);
865 }
866 mutex_unlock(&chip->mutex);
867 return changed;
868}
869
870static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
871{
872 static const char *const names[2] = {
873 "None", "High-pass Filter"
874 };
875
876 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
877 info->count = 1;
878 info->value.enumerated.items = 2;
879 if (info->value.enumerated.item >= 2)
880 info->value.enumerated.item = 1;
881 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
882 return 0;
883}
884
885static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
886{
887 struct oxygen *chip = ctl->private_data;
888 struct xonar_wm87x6 *data = chip->model_data;
889
890 value->value.enumerated.item[0] =
891 !(data->wm8776_regs[WM8776_ADCIFCTRL] & WM8776_ADCHPD);
892 return 0;
893}
894
895static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
896{
897 struct oxygen *chip = ctl->private_data;
898 struct xonar_wm87x6 *data = chip->model_data;
899 unsigned int reg;
900 int changed;
901
902 mutex_lock(&chip->mutex);
903 reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD;
904 if (!value->value.enumerated.item[0])
905 reg |= WM8776_ADCHPD;
906 changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL];
907 if (changed)
908 wm8776_write(chip, WM8776_ADCIFCTRL, reg);
909 mutex_unlock(&chip->mutex);
910 return changed;
911}
912
913#define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \
914 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
915 .name = xname, \
916 .info = snd_ctl_boolean_mono_info, \
917 .get = wm8776_bit_switch_get, \
918 .put = wm8776_bit_switch_put, \
919 .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \
920}
921#define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \
922 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
923 .name = xname, \
924 .private_value = (initval) | ((min) << 8) | ((max) << 12) | \
925 ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags)
926#define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\
927 _WM8776_FIELD_CTL(xname " Capture Enum", \
928 reg, shift, init, min, max, mask, flags), \
929 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
930 SNDRV_CTL_ELEM_ACCESS_INACTIVE, \
931 .info = wm8776_field_enum_info, \
932 .get = wm8776_field_enum_get, \
933 .put = wm8776_field_enum_put, \
934}
935#define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \
936 _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \
937 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
938 SNDRV_CTL_ELEM_ACCESS_INACTIVE | \
939 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
940 .info = wm8776_field_volume_info, \
941 .get = wm8776_field_volume_get, \
942 .put = wm8776_field_volume_put, \
943 .tlv = { .p = tlv_p }, \
944}
945
946static const DECLARE_TLV_DB_SCALE(wm87x6_dac_db_scale, -6000, 50, 0);
947static const DECLARE_TLV_DB_SCALE(wm8776_adc_db_scale, -2100, 50, 0);
948static const DECLARE_TLV_DB_SCALE(wm8776_hp_db_scale, -6000, 100, 0);
949static const DECLARE_TLV_DB_SCALE(wm8776_lct_db_scale, -1600, 100, 0);
950static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_db_scale, 0, 400, 0);
951static const DECLARE_TLV_DB_SCALE(wm8776_ngth_db_scale, -7800, 600, 0);
952static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_db_scale, -1200, 100, 0);
953static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_db_scale, -2100, 400, 0);
954
955static const struct snd_kcontrol_new ds_controls[] = {
956 {
957 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
958 .name = "Headphone Playback Volume",
959 .info = wm8776_hp_vol_info,
960 .get = wm8776_hp_vol_get,
961 .put = wm8776_hp_vol_put,
962 .tlv = { .p = wm8776_hp_db_scale },
963 },
964 WM8776_BIT_SWITCH("Headphone Playback Switch",
965 WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
966 {
967 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
968 .name = "Input Capture Volume",
969 .info = wm8776_input_vol_info,
970 .get = wm8776_input_vol_get,
971 .put = wm8776_input_vol_put,
972 .tlv = { .p = wm8776_adc_db_scale },
973 },
974 {
975 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
976 .name = "Line Capture Switch",
977 .info = snd_ctl_boolean_mono_info,
978 .get = wm8776_input_mux_get,
979 .put = wm8776_input_mux_put,
980 .private_value = 1 << 0,
981 },
982 {
983 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
984 .name = "Mic Capture Switch",
985 .info = snd_ctl_boolean_mono_info,
986 .get = wm8776_input_mux_get,
987 .put = wm8776_input_mux_put,
988 .private_value = 1 << 1,
989 },
Clemens Ladisch9bac84e2010-09-09 12:19:21 +0200990 WM8776_BIT_SWITCH("Front Mic Capture Switch",
991 WM8776_ADCMUX, 1 << 2, 0, 0),
992 WM8776_BIT_SWITCH("Aux Capture Switch",
993 WM8776_ADCMUX, 1 << 3, 0, 0),
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100994 {
995 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
996 .name = "ADC Filter Capture Enum",
997 .info = hpf_info,
998 .get = hpf_get,
999 .put = hpf_put,
1000 },
1001 {
1002 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1003 .name = "Level Control Capture Enum",
1004 .info = wm8776_level_control_info,
1005 .get = wm8776_level_control_get,
1006 .put = wm8776_level_control_put,
1007 .private_value = 0,
1008 },
1009};
1010static const struct snd_kcontrol_new lc_controls[] = {
1011 WM8776_FIELD_CTL_VOLUME("Limiter Threshold",
1012 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
1013 LC_CONTROL_LIMITER, wm8776_lct_db_scale),
1014 WM8776_FIELD_CTL_ENUM("Limiter Attack Time",
1015 WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
1016 LC_CONTROL_LIMITER),
1017 WM8776_FIELD_CTL_ENUM("Limiter Decay Time",
1018 WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
1019 LC_CONTROL_LIMITER),
1020 WM8776_FIELD_CTL_ENUM("Limiter Transient Window",
1021 WM8776_LIMITER, 4, 2, 0, 7, 0x7,
1022 LC_CONTROL_LIMITER),
1023 WM8776_FIELD_CTL_VOLUME("Limiter Maximum Attenuation",
1024 WM8776_LIMITER, 0, 6, 3, 12, 0xf,
1025 LC_CONTROL_LIMITER,
1026 wm8776_maxatten_lim_db_scale),
1027 WM8776_FIELD_CTL_VOLUME("ALC Target Level",
1028 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
1029 LC_CONTROL_ALC, wm8776_lct_db_scale),
1030 WM8776_FIELD_CTL_ENUM("ALC Attack Time",
1031 WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
1032 LC_CONTROL_ALC),
1033 WM8776_FIELD_CTL_ENUM("ALC Decay Time",
1034 WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
1035 LC_CONTROL_ALC),
1036 WM8776_FIELD_CTL_VOLUME("ALC Maximum Gain",
1037 WM8776_ALCCTRL1, 4, 7, 1, 7, 0x7,
1038 LC_CONTROL_ALC, wm8776_maxgain_db_scale),
1039 WM8776_FIELD_CTL_VOLUME("ALC Maximum Attenuation",
1040 WM8776_LIMITER, 0, 10, 10, 15, 0xf,
1041 LC_CONTROL_ALC, wm8776_maxatten_alc_db_scale),
1042 WM8776_FIELD_CTL_ENUM("ALC Hold Time",
1043 WM8776_ALCCTRL2, 0, 0, 0, 15, 0xf,
1044 LC_CONTROL_ALC),
1045 WM8776_BIT_SWITCH("Noise Gate Capture Switch",
1046 WM8776_NOISEGATE, WM8776_NGAT, 0,
1047 LC_CONTROL_ALC),
1048 WM8776_FIELD_CTL_VOLUME("Noise Gate Threshold",
1049 WM8776_NOISEGATE, 2, 0, 0, 7, 0x7,
1050 LC_CONTROL_ALC, wm8776_ngth_db_scale),
1051};
1052
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001053static int xonar_ds_mixer_init(struct oxygen *chip)
1054{
1055 struct xonar_wm87x6 *data = chip->model_data;
1056 unsigned int i;
1057 struct snd_kcontrol *ctl;
1058 int err;
1059
1060 for (i = 0; i < ARRAY_SIZE(ds_controls); ++i) {
1061 ctl = snd_ctl_new1(&ds_controls[i], chip);
1062 if (!ctl)
1063 return -ENOMEM;
1064 err = snd_ctl_add(chip->card, ctl);
1065 if (err < 0)
1066 return err;
Clemens Ladischfe6ce802010-09-07 13:38:49 +02001067 if (!strcmp(ctl->id.name, "Line Capture Switch"))
1068 data->line_adcmux_control = ctl;
1069 else if (!strcmp(ctl->id.name, "Mic Capture Switch"))
1070 data->mic_adcmux_control = ctl;
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001071 }
Clemens Ladischfe6ce802010-09-07 13:38:49 +02001072 if (!data->line_adcmux_control || !data->mic_adcmux_control)
1073 return -ENXIO;
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001074 BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
1075 for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
1076 ctl = snd_ctl_new1(&lc_controls[i], chip);
1077 if (!ctl)
1078 return -ENOMEM;
1079 err = snd_ctl_add(chip->card, ctl);
1080 if (err < 0)
1081 return err;
1082 data->lc_controls[i] = ctl;
1083 }
1084 return 0;
1085}
1086
Clemens Ladisch9719fca2010-12-02 11:41:10 +01001087static void dump_wm8776_registers(struct oxygen *chip,
1088 struct snd_info_buffer *buffer)
1089{
1090 struct xonar_wm87x6 *data = chip->model_data;
1091 unsigned int i;
1092
1093 snd_iprintf(buffer, "\nWM8776:\n00:");
1094 for (i = 0; i < 0x10; ++i)
1095 snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
1096 snd_iprintf(buffer, "\n10:");
1097 for (i = 0x10; i < 0x17; ++i)
1098 snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
1099 snd_iprintf(buffer, "\n");
1100}
1101
1102static void dump_wm87x6_registers(struct oxygen *chip,
1103 struct snd_info_buffer *buffer)
1104{
1105 struct xonar_wm87x6 *data = chip->model_data;
1106 unsigned int i;
1107
1108 dump_wm8776_registers(chip, buffer);
1109 snd_iprintf(buffer, "\nWM8766:\n00:");
1110 for (i = 0; i < 0x10; ++i)
1111 snd_iprintf(buffer, " %03x", data->wm8766_regs[i]);
1112 snd_iprintf(buffer, "\n");
1113}
1114
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001115static const struct oxygen_model model_xonar_ds = {
1116 .shortname = "Xonar DS",
Clemens Ladisch45bc3072010-10-04 13:17:26 +02001117 .longname = "Asus Virtuoso 66",
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001118 .chip = "AV200",
1119 .init = xonar_ds_init,
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001120 .mixer_init = xonar_ds_mixer_init,
1121 .cleanup = xonar_ds_cleanup,
1122 .suspend = xonar_ds_suspend,
1123 .resume = xonar_ds_resume,
1124 .pcm_hardware_filter = wm8776_adc_hardware_filter,
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001125 .set_dac_params = set_wm87x6_dac_params,
1126 .set_adc_params = set_wm8776_adc_params,
1127 .update_dac_volume = update_wm87x6_volume,
1128 .update_dac_mute = update_wm87x6_mute,
Clemens Ladisch2dbf0ea2010-09-09 12:24:35 +02001129 .update_center_lfe_mix = update_wm8766_center_lfe_mix,
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001130 .gpio_changed = xonar_ds_gpio_changed,
Clemens Ladisch9719fca2010-12-02 11:41:10 +01001131 .dump_registers = dump_wm87x6_registers,
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001132 .dac_tlv = wm87x6_dac_db_scale,
1133 .model_data_size = sizeof(struct xonar_wm87x6),
1134 .device_config = PLAYBACK_0_TO_I2S |
1135 PLAYBACK_1_TO_SPDIF |
1136 CAPTURE_0_FROM_I2S_1,
Clemens Ladisch1f4d7be2011-01-10 15:59:38 +01001137 .dac_channels_pcm = 8,
1138 .dac_channels_mixer = 8,
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001139 .dac_volume_min = 255 - 2*60,
1140 .dac_volume_max = 255,
1141 .function_flags = OXYGEN_FUNCTION_SPI,
Clemens Ladisch5b8bf2a2011-01-10 16:14:52 +01001142 .dac_mclks = OXYGEN_MCLKS(256, 256, 128),
1143 .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001144 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1145 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1146};
1147
1148int __devinit get_xonar_wm87x6_model(struct oxygen *chip,
1149 const struct pci_device_id *id)
1150{
1151 switch (id->subdevice) {
1152 case 0x838e:
1153 chip->model = model_xonar_ds;
1154 break;
1155 default:
1156 return -EINVAL;
1157 }
1158 return 0;
1159}