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