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