1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * card driver for models with WM8776/WM8766 DACs (Xonar DS/HDAV1.3 Slim)
4 *
5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
6 */
7
8/*
9 * Xonar DS
10 * --------
11 *
12 * CMI8788:
13 *
14 * SPI 0 -> WM8766 (surround, center/LFE, back)
15 * SPI 1 -> WM8776 (front, input)
16 *
17 * GPIO 4 <- headphone detect, 0 = plugged
18 * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
19 * GPIO 7 -> enable output to front L/R speaker channels
20 * GPIO 8 -> enable output to other speaker channels and front panel headphone
21 *
22 * WM8776:
23 *
24 * input 1 <- line
25 * input 2 <- mic
26 * input 3 <- front mic
27 * input 4 <- aux
28 */
29
30/*
31 * Xonar HDAV1.3 Slim
32 * ------------------
33 *
34 * CMI8788:
35 *
36 * I²C <-> WM8776 (addr 0011010)
37 *
38 * GPIO 0 -> disable HDMI output
39 * GPIO 1 -> enable HP output
40 * GPIO 6 -> firmware EEPROM I²C clock
41 * GPIO 7 <-> firmware EEPROM I²C data
42 *
43 * UART <-> HDMI controller
44 *
45 * WM8776:
46 *
47 * input 1 <- mic
48 * input 2 <- aux
49 */
50
51#include <linux/pci.h>
52#include <linux/delay.h>
53#include <sound/control.h>
54#include <sound/core.h>
55#include <sound/info.h>
56#include <sound/jack.h>
57#include <sound/pcm.h>
58#include <sound/pcm_params.h>
59#include <sound/tlv.h>
60#include "xonar.h"
61#include "wm8776.h"
62#include "wm8766.h"
63
64#define GPIO_DS_HP_DETECT 0x0010
65#define GPIO_DS_INPUT_ROUTE 0x0040
66#define GPIO_DS_OUTPUT_FRONTLR 0x0080
67#define GPIO_DS_OUTPUT_ENABLE 0x0100
68
69#define GPIO_SLIM_HDMI_DISABLE 0x0001
70#define GPIO_SLIM_OUTPUT_ENABLE 0x0002
71#define GPIO_SLIM_FIRMWARE_CLK 0x0040
72#define GPIO_SLIM_FIRMWARE_DATA 0x0080
73
74#define I2C_DEVICE_WM8776 0x34 /* 001101, 0, /W=0 */
75
76#define LC_CONTROL_LIMITER 0x40000000
77#define LC_CONTROL_ALC 0x20000000
78
79struct xonar_wm87x6 {
80 struct xonar_generic generic;
81 u16 wm8776_regs[0x17];
82 u16 wm8766_regs[0x10];
83 struct snd_kcontrol *line_adcmux_control;
84 struct snd_kcontrol *mic_adcmux_control;
85 struct snd_kcontrol *lc_controls[13];
86 struct snd_jack *hp_jack;
87 struct xonar_hdmi hdmi;
88};
89
90static void wm8776_write_spi(struct oxygen *chip,
91 unsigned int reg, unsigned int value)
92{
93 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
94 OXYGEN_SPI_DATA_LENGTH_2 |
95 OXYGEN_SPI_CLOCK_160 |
96 (1 << OXYGEN_SPI_CODEC_SHIFT) |
97 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
98 data: (reg << 9) | value);
99}
100
101static void wm8776_write_i2c(struct oxygen *chip,
102 unsigned int reg, unsigned int value)
103{
104 oxygen_write_i2c(chip, I2C_DEVICE_WM8776,
105 map: (reg << 1) | (value >> 8), data: value);
106}
107
108static void wm8776_write(struct oxygen *chip,
109 unsigned int reg, unsigned int value)
110{
111 struct xonar_wm87x6 *data = chip->model_data;
112
113 if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
114 OXYGEN_FUNCTION_SPI)
115 wm8776_write_spi(chip, reg, value);
116 else
117 wm8776_write_i2c(chip, reg, value);
118 if (reg < ARRAY_SIZE(data->wm8776_regs)) {
119 /* reg >= WM8776_HPLVOL is always true */
120 if (reg <= WM8776_DACMASTER)
121 value &= ~WM8776_UPDATE;
122 data->wm8776_regs[reg] = value;
123 }
124}
125
126static void wm8776_write_cached(struct oxygen *chip,
127 unsigned int reg, unsigned int value)
128{
129 struct xonar_wm87x6 *data = chip->model_data;
130
131 if (reg >= ARRAY_SIZE(data->wm8776_regs) ||
132 value != data->wm8776_regs[reg])
133 wm8776_write(chip, reg, value);
134}
135
136static void wm8766_write(struct oxygen *chip,
137 unsigned int reg, unsigned int value)
138{
139 struct xonar_wm87x6 *data = chip->model_data;
140
141 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
142 OXYGEN_SPI_DATA_LENGTH_2 |
143 OXYGEN_SPI_CLOCK_160 |
144 (0 << OXYGEN_SPI_CODEC_SHIFT) |
145 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
146 data: (reg << 9) | value);
147 if (reg < ARRAY_SIZE(data->wm8766_regs)) {
148 /* reg >= WM8766_LDA1 is always true */
149 if (reg <= WM8766_RDA1 ||
150 (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
151 value &= ~WM8766_UPDATE;
152 data->wm8766_regs[reg] = value;
153 }
154}
155
156static void wm8766_write_cached(struct oxygen *chip,
157 unsigned int reg, unsigned int value)
158{
159 struct xonar_wm87x6 *data = chip->model_data;
160
161 if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
162 value != data->wm8766_regs[reg])
163 wm8766_write(chip, reg, value);
164}
165
166static void wm8776_registers_init(struct oxygen *chip)
167{
168 struct xonar_wm87x6 *data = chip->model_data;
169
170 wm8776_write(chip, WM8776_RESET, value: 0);
171 wm8776_write(chip, WM8776_PHASESWAP, WM8776_PH_MASK);
172 wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN |
173 WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT);
174 wm8776_write(chip, WM8776_DACMUTE, value: chip->dac_mute ? WM8776_DMUTE : 0);
175 wm8776_write(chip, WM8776_DACIFCTRL,
176 WM8776_DACFMT_LJUST | WM8776_DACWL_24);
177 wm8776_write(chip, WM8776_ADCIFCTRL,
178 value: data->wm8776_regs[WM8776_ADCIFCTRL]);
179 wm8776_write(chip, WM8776_MSTRCTRL, value: data->wm8776_regs[WM8776_MSTRCTRL]);
180 wm8776_write(chip, WM8776_PWRDOWN, value: data->wm8776_regs[WM8776_PWRDOWN]);
181 wm8776_write(chip, WM8776_HPLVOL, value: data->wm8776_regs[WM8776_HPLVOL]);
182 wm8776_write(chip, WM8776_HPRVOL, value: data->wm8776_regs[WM8776_HPRVOL] |
183 WM8776_UPDATE);
184 wm8776_write(chip, WM8776_ADCLVOL, value: data->wm8776_regs[WM8776_ADCLVOL]);
185 wm8776_write(chip, WM8776_ADCRVOL, value: data->wm8776_regs[WM8776_ADCRVOL]);
186 wm8776_write(chip, WM8776_ADCMUX, value: data->wm8776_regs[WM8776_ADCMUX]);
187 wm8776_write(chip, WM8776_DACLVOL, value: chip->dac_volume[0]);
188 wm8776_write(chip, WM8776_DACRVOL, value: chip->dac_volume[1] | WM8776_UPDATE);
189}
190
191static void wm8766_registers_init(struct oxygen *chip)
192{
193 struct xonar_wm87x6 *data = chip->model_data;
194
195 wm8766_write(chip, WM8766_RESET, value: 0);
196 wm8766_write(chip, WM8766_DAC_CTRL, value: data->wm8766_regs[WM8766_DAC_CTRL]);
197 wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
198 wm8766_write(chip, WM8766_DAC_CTRL2,
199 WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
200 wm8766_write(chip, WM8766_LDA1, value: chip->dac_volume[2]);
201 wm8766_write(chip, WM8766_RDA1, value: chip->dac_volume[3]);
202 wm8766_write(chip, WM8766_LDA2, value: chip->dac_volume[4]);
203 wm8766_write(chip, WM8766_RDA2, value: chip->dac_volume[5]);
204 wm8766_write(chip, WM8766_LDA3, value: chip->dac_volume[6]);
205 wm8766_write(chip, WM8766_RDA3, value: chip->dac_volume[7] | WM8766_UPDATE);
206}
207
208static void wm8776_init(struct oxygen *chip)
209{
210 struct xonar_wm87x6 *data = chip->model_data;
211
212 data->wm8776_regs[WM8776_HPLVOL] = (0x79 - 60) | WM8776_HPZCEN;
213 data->wm8776_regs[WM8776_HPRVOL] = (0x79 - 60) | WM8776_HPZCEN;
214 data->wm8776_regs[WM8776_ADCIFCTRL] =
215 WM8776_ADCFMT_LJUST | WM8776_ADCWL_24 | WM8776_ADCMCLK;
216 data->wm8776_regs[WM8776_MSTRCTRL] =
217 WM8776_ADCRATE_256 | WM8776_DACRATE_256;
218 data->wm8776_regs[WM8776_PWRDOWN] = WM8776_HPPD;
219 data->wm8776_regs[WM8776_ADCLVOL] = 0xa5 | WM8776_ZCA;
220 data->wm8776_regs[WM8776_ADCRVOL] = 0xa5 | WM8776_ZCA;
221 data->wm8776_regs[WM8776_ADCMUX] = 0x001;
222 wm8776_registers_init(chip);
223}
224
225static void wm8766_init(struct oxygen *chip)
226{
227 struct xonar_wm87x6 *data = chip->model_data;
228
229 data->wm8766_regs[WM8766_DAC_CTRL] =
230 WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
231 wm8766_registers_init(chip);
232}
233
234static void xonar_ds_handle_hp_jack(struct oxygen *chip)
235{
236 struct xonar_wm87x6 *data = chip->model_data;
237 bool hp_plugged;
238 unsigned int reg;
239
240 mutex_lock(&chip->mutex);
241
242 hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
243 GPIO_DS_HP_DETECT);
244
245 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
246 value: hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
247 GPIO_DS_OUTPUT_FRONTLR);
248
249 reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
250 if (hp_plugged)
251 reg |= WM8766_MUTEALL;
252 wm8766_write_cached(chip, WM8766_DAC_CTRL, value: reg);
253
254 snd_jack_report(jack: data->hp_jack, status: hp_plugged ? SND_JACK_HEADPHONE : 0);
255
256 mutex_unlock(lock: &chip->mutex);
257}
258
259static void xonar_ds_init(struct oxygen *chip)
260{
261 struct xonar_wm87x6 *data = chip->model_data;
262
263 data->generic.anti_pop_delay = 300;
264 data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
265
266 wm8776_init(chip);
267 wm8766_init(chip);
268
269 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
270 GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
271 oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
272 GPIO_DS_HP_DETECT);
273 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
274 oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
275 chip->interrupt_mask |= OXYGEN_INT_GPIO;
276
277 xonar_enable_output(chip);
278
279 snd_jack_new(card: chip->card, id: "Headphone",
280 type: SND_JACK_HEADPHONE, jack: &data->hp_jack, initial_kctl: false, phantom_jack: false);
281 xonar_ds_handle_hp_jack(chip);
282
283 snd_component_add(card: chip->card, component: "WM8776");
284 snd_component_add(card: chip->card, component: "WM8766");
285}
286
287static void xonar_hdav_slim_init(struct oxygen *chip)
288{
289 struct xonar_wm87x6 *data = chip->model_data;
290
291 data->generic.anti_pop_delay = 300;
292 data->generic.output_enable_bit = GPIO_SLIM_OUTPUT_ENABLE;
293
294 wm8776_init(chip);
295
296 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
297 GPIO_SLIM_HDMI_DISABLE |
298 GPIO_SLIM_FIRMWARE_CLK |
299 GPIO_SLIM_FIRMWARE_DATA);
300
301 xonar_hdmi_init(chip, data: &data->hdmi);
302 xonar_enable_output(chip);
303
304 snd_component_add(card: chip->card, component: "WM8776");
305}
306
307static void xonar_ds_cleanup(struct oxygen *chip)
308{
309 xonar_disable_output(chip);
310 wm8776_write(chip, WM8776_RESET, value: 0);
311}
312
313static void xonar_hdav_slim_cleanup(struct oxygen *chip)
314{
315 xonar_hdmi_cleanup(chip);
316 xonar_disable_output(chip);
317 wm8776_write(chip, WM8776_RESET, value: 0);
318 msleep(msecs: 2);
319}
320
321static void xonar_ds_suspend(struct oxygen *chip)
322{
323 xonar_ds_cleanup(chip);
324}
325
326static void xonar_hdav_slim_suspend(struct oxygen *chip)
327{
328 xonar_hdav_slim_cleanup(chip);
329}
330
331static void xonar_ds_resume(struct oxygen *chip)
332{
333 wm8776_registers_init(chip);
334 wm8766_registers_init(chip);
335 xonar_enable_output(chip);
336 xonar_ds_handle_hp_jack(chip);
337}
338
339static void xonar_hdav_slim_resume(struct oxygen *chip)
340{
341 struct xonar_wm87x6 *data = chip->model_data;
342
343 wm8776_registers_init(chip);
344 xonar_hdmi_resume(chip, hdmi: &data->hdmi);
345 xonar_enable_output(chip);
346}
347
348static void wm8776_adc_hardware_filter(unsigned int channel,
349 struct snd_pcm_hardware *hardware)
350{
351 if (channel == PCM_A) {
352 hardware->rates = SNDRV_PCM_RATE_32000 |
353 SNDRV_PCM_RATE_44100 |
354 SNDRV_PCM_RATE_48000 |
355 SNDRV_PCM_RATE_64000 |
356 SNDRV_PCM_RATE_88200 |
357 SNDRV_PCM_RATE_96000;
358 hardware->rate_max = 96000;
359 }
360}
361
362static void xonar_hdav_slim_hardware_filter(unsigned int channel,
363 struct snd_pcm_hardware *hardware)
364{
365 wm8776_adc_hardware_filter(channel, hardware);
366 xonar_hdmi_pcm_hardware_filter(channel, hardware);
367}
368
369static void set_wm87x6_dac_params(struct oxygen *chip,
370 struct snd_pcm_hw_params *params)
371{
372}
373
374static void set_wm8776_adc_params(struct oxygen *chip,
375 struct snd_pcm_hw_params *params)
376{
377 u16 reg;
378
379 reg = WM8776_ADCRATE_256 | WM8776_DACRATE_256;
380 if (params_rate(p: params) > 48000)
381 reg |= WM8776_ADCOSR;
382 wm8776_write_cached(chip, WM8776_MSTRCTRL, value: reg);
383}
384
385static void set_hdav_slim_dac_params(struct oxygen *chip,
386 struct snd_pcm_hw_params *params)
387{
388 struct xonar_wm87x6 *data = chip->model_data;
389
390 xonar_set_hdmi_params(chip, hdmi: &data->hdmi, params);
391}
392
393static void update_wm8776_volume(struct oxygen *chip)
394{
395 struct xonar_wm87x6 *data = chip->model_data;
396 u8 to_change;
397
398 if (chip->dac_volume[0] == chip->dac_volume[1]) {
399 if (chip->dac_volume[0] != data->wm8776_regs[WM8776_DACLVOL] ||
400 chip->dac_volume[1] != data->wm8776_regs[WM8776_DACRVOL]) {
401 wm8776_write(chip, WM8776_DACMASTER,
402 value: chip->dac_volume[0] | WM8776_UPDATE);
403 data->wm8776_regs[WM8776_DACLVOL] = chip->dac_volume[0];
404 data->wm8776_regs[WM8776_DACRVOL] = chip->dac_volume[0];
405 }
406 } else {
407 to_change = (chip->dac_volume[0] !=
408 data->wm8776_regs[WM8776_DACLVOL]) << 0;
409 to_change |= (chip->dac_volume[1] !=
410 data->wm8776_regs[WM8776_DACLVOL]) << 1;
411 if (to_change & 1)
412 wm8776_write(chip, WM8776_DACLVOL, value: chip->dac_volume[0] |
413 ((to_change & 2) ? 0 : WM8776_UPDATE));
414 if (to_change & 2)
415 wm8776_write(chip, WM8776_DACRVOL,
416 value: chip->dac_volume[1] | WM8776_UPDATE);
417 }
418}
419
420static void update_wm87x6_volume(struct oxygen *chip)
421{
422 static const u8 wm8766_regs[6] = {
423 WM8766_LDA1, WM8766_RDA1,
424 WM8766_LDA2, WM8766_RDA2,
425 WM8766_LDA3, WM8766_RDA3,
426 };
427 struct xonar_wm87x6 *data = chip->model_data;
428 unsigned int i;
429 u8 to_change;
430
431 update_wm8776_volume(chip);
432 if (chip->dac_volume[2] == chip->dac_volume[3] &&
433 chip->dac_volume[2] == chip->dac_volume[4] &&
434 chip->dac_volume[2] == chip->dac_volume[5] &&
435 chip->dac_volume[2] == chip->dac_volume[6] &&
436 chip->dac_volume[2] == chip->dac_volume[7]) {
437 to_change = 0;
438 for (i = 0; i < 6; ++i)
439 if (chip->dac_volume[2] !=
440 data->wm8766_regs[wm8766_regs[i]])
441 to_change = 1;
442 if (to_change) {
443 wm8766_write(chip, WM8766_MASTDA,
444 value: chip->dac_volume[2] | WM8766_UPDATE);
445 for (i = 0; i < 6; ++i)
446 data->wm8766_regs[wm8766_regs[i]] =
447 chip->dac_volume[2];
448 }
449 } else {
450 to_change = 0;
451 for (i = 0; i < 6; ++i)
452 to_change |= (chip->dac_volume[2 + i] !=
453 data->wm8766_regs[wm8766_regs[i]]) << i;
454 for (i = 0; i < 6; ++i)
455 if (to_change & (1 << i))
456 wm8766_write(chip, reg: wm8766_regs[i],
457 value: chip->dac_volume[2 + i] |
458 ((to_change & (0x3e << i))
459 ? 0 : WM8766_UPDATE));
460 }
461}
462
463static void update_wm8776_mute(struct oxygen *chip)
464{
465 wm8776_write_cached(chip, WM8776_DACMUTE,
466 value: chip->dac_mute ? WM8776_DMUTE : 0);
467}
468
469static void update_wm87x6_mute(struct oxygen *chip)
470{
471 update_wm8776_mute(chip);
472 wm8766_write_cached(chip, WM8766_DAC_CTRL2, WM8766_ZCD |
473 (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
474}
475
476static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
477{
478 struct xonar_wm87x6 *data = chip->model_data;
479 unsigned int reg;
480
481 /*
482 * The WM8766 can mix left and right channels, but this setting
483 * applies to all three stereo pairs.
484 */
485 reg = data->wm8766_regs[WM8766_DAC_CTRL] &
486 ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
487 if (mixed)
488 reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
489 else
490 reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
491 wm8766_write_cached(chip, WM8766_DAC_CTRL, value: reg);
492}
493
494static void xonar_ds_gpio_changed(struct oxygen *chip)
495{
496 xonar_ds_handle_hp_jack(chip);
497}
498
499static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
500 struct snd_ctl_elem_value *value)
501{
502 struct oxygen *chip = ctl->private_data;
503 struct xonar_wm87x6 *data = chip->model_data;
504 u16 bit = ctl->private_value & 0xffff;
505 unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
506 bool invert = (ctl->private_value >> 24) & 1;
507
508 value->value.integer.value[0] =
509 ((data->wm8776_regs[reg_index] & bit) != 0) ^ invert;
510 return 0;
511}
512
513static int wm8776_bit_switch_put(struct snd_kcontrol *ctl,
514 struct snd_ctl_elem_value *value)
515{
516 struct oxygen *chip = ctl->private_data;
517 struct xonar_wm87x6 *data = chip->model_data;
518 u16 bit = ctl->private_value & 0xffff;
519 u16 reg_value;
520 unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
521 bool invert = (ctl->private_value >> 24) & 1;
522 int changed;
523
524 mutex_lock(&chip->mutex);
525 reg_value = data->wm8776_regs[reg_index] & ~bit;
526 if (value->value.integer.value[0] ^ invert)
527 reg_value |= bit;
528 changed = reg_value != data->wm8776_regs[reg_index];
529 if (changed)
530 wm8776_write(chip, reg: reg_index, value: reg_value);
531 mutex_unlock(lock: &chip->mutex);
532 return changed;
533}
534
535static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
536 struct snd_ctl_elem_info *info)
537{
538 static const char *const hld[16] = {
539 "0 ms", "2.67 ms", "5.33 ms", "10.6 ms",
540 "21.3 ms", "42.7 ms", "85.3 ms", "171 ms",
541 "341 ms", "683 ms", "1.37 s", "2.73 s",
542 "5.46 s", "10.9 s", "21.8 s", "43.7 s",
543 };
544 static const char *const atk_lim[11] = {
545 "0.25 ms", "0.5 ms", "1 ms", "2 ms",
546 "4 ms", "8 ms", "16 ms", "32 ms",
547 "64 ms", "128 ms", "256 ms",
548 };
549 static const char *const atk_alc[11] = {
550 "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms",
551 "134 ms", "269 ms", "538 ms", "1.08 s",
552 "2.15 s", "4.3 s", "8.6 s",
553 };
554 static const char *const dcy_lim[11] = {
555 "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms",
556 "19.2 ms", "38.4 ms", "76.8 ms", "154 ms",
557 "307 ms", "614 ms", "1.23 s",
558 };
559 static const char *const dcy_alc[11] = {
560 "33.5 ms", "67.0 ms", "134 ms", "268 ms",
561 "536 ms", "1.07 s", "2.14 s", "4.29 s",
562 "8.58 s", "17.2 s", "34.3 s",
563 };
564 static const char *const tranwin[8] = {
565 "0 us", "62.5 us", "125 us", "250 us",
566 "500 us", "1 ms", "2 ms", "4 ms",
567 };
568 u8 max;
569 const char *const *names;
570
571 max = (ctl->private_value >> 12) & 0xf;
572 switch ((ctl->private_value >> 24) & 0x1f) {
573 case WM8776_ALCCTRL2:
574 names = hld;
575 break;
576 case WM8776_ALCCTRL3:
577 if (((ctl->private_value >> 20) & 0xf) == 0) {
578 if (ctl->private_value & LC_CONTROL_LIMITER)
579 names = atk_lim;
580 else
581 names = atk_alc;
582 } else {
583 if (ctl->private_value & LC_CONTROL_LIMITER)
584 names = dcy_lim;
585 else
586 names = dcy_alc;
587 }
588 break;
589 case WM8776_LIMITER:
590 names = tranwin;
591 break;
592 default:
593 return -ENXIO;
594 }
595 return snd_ctl_enum_info(info, channels: 1, items: max + 1, names);
596}
597
598static int wm8776_field_volume_info(struct snd_kcontrol *ctl,
599 struct snd_ctl_elem_info *info)
600{
601 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
602 info->count = 1;
603 info->value.integer.min = (ctl->private_value >> 8) & 0xf;
604 info->value.integer.max = (ctl->private_value >> 12) & 0xf;
605 return 0;
606}
607
608static void wm8776_field_set_from_ctl(struct snd_kcontrol *ctl)
609{
610 struct oxygen *chip = ctl->private_data;
611 struct xonar_wm87x6 *data = chip->model_data;
612 unsigned int value, reg_index, mode;
613 u8 min, max, shift;
614 u16 mask, reg_value;
615 bool invert;
616
617 if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
618 WM8776_LCSEL_LIMITER)
619 mode = LC_CONTROL_LIMITER;
620 else
621 mode = LC_CONTROL_ALC;
622 if (!(ctl->private_value & mode))
623 return;
624
625 value = ctl->private_value & 0xf;
626 min = (ctl->private_value >> 8) & 0xf;
627 max = (ctl->private_value >> 12) & 0xf;
628 mask = (ctl->private_value >> 16) & 0xf;
629 shift = (ctl->private_value >> 20) & 0xf;
630 reg_index = (ctl->private_value >> 24) & 0x1f;
631 invert = (ctl->private_value >> 29) & 0x1;
632
633 if (invert)
634 value = max - (value - min);
635 reg_value = data->wm8776_regs[reg_index];
636 reg_value &= ~(mask << shift);
637 reg_value |= value << shift;
638 wm8776_write_cached(chip, reg: reg_index, value: reg_value);
639}
640
641static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value)
642{
643 struct oxygen *chip = ctl->private_data;
644 u8 min, max;
645 int changed;
646
647 min = (ctl->private_value >> 8) & 0xf;
648 max = (ctl->private_value >> 12) & 0xf;
649 if (value < min || value > max)
650 return -EINVAL;
651 mutex_lock(&chip->mutex);
652 changed = value != (ctl->private_value & 0xf);
653 if (changed) {
654 ctl->private_value = (ctl->private_value & ~0xf) | value;
655 wm8776_field_set_from_ctl(ctl);
656 }
657 mutex_unlock(lock: &chip->mutex);
658 return changed;
659}
660
661static int wm8776_field_enum_get(struct snd_kcontrol *ctl,
662 struct snd_ctl_elem_value *value)
663{
664 value->value.enumerated.item[0] = ctl->private_value & 0xf;
665 return 0;
666}
667
668static int wm8776_field_volume_get(struct snd_kcontrol *ctl,
669 struct snd_ctl_elem_value *value)
670{
671 value->value.integer.value[0] = ctl->private_value & 0xf;
672 return 0;
673}
674
675static int wm8776_field_enum_put(struct snd_kcontrol *ctl,
676 struct snd_ctl_elem_value *value)
677{
678 return wm8776_field_set(ctl, value: value->value.enumerated.item[0]);
679}
680
681static int wm8776_field_volume_put(struct snd_kcontrol *ctl,
682 struct snd_ctl_elem_value *value)
683{
684 return wm8776_field_set(ctl, value: value->value.integer.value[0]);
685}
686
687static int wm8776_hp_vol_info(struct snd_kcontrol *ctl,
688 struct snd_ctl_elem_info *info)
689{
690 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
691 info->count = 2;
692 info->value.integer.min = 0x79 - 60;
693 info->value.integer.max = 0x7f;
694 return 0;
695}
696
697static int wm8776_hp_vol_get(struct snd_kcontrol *ctl,
698 struct snd_ctl_elem_value *value)
699{
700 struct oxygen *chip = ctl->private_data;
701 struct xonar_wm87x6 *data = chip->model_data;
702
703 mutex_lock(&chip->mutex);
704 value->value.integer.value[0] =
705 data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK;
706 value->value.integer.value[1] =
707 data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK;
708 mutex_unlock(lock: &chip->mutex);
709 return 0;
710}
711
712static int wm8776_hp_vol_put(struct snd_kcontrol *ctl,
713 struct snd_ctl_elem_value *value)
714{
715 struct oxygen *chip = ctl->private_data;
716 struct xonar_wm87x6 *data = chip->model_data;
717 u8 to_update;
718
719 mutex_lock(&chip->mutex);
720 to_update = (value->value.integer.value[0] !=
721 (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK))
722 << 0;
723 to_update |= (value->value.integer.value[1] !=
724 (data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK))
725 << 1;
726 if (value->value.integer.value[0] == value->value.integer.value[1]) {
727 if (to_update) {
728 wm8776_write(chip, WM8776_HPMASTER,
729 value: value->value.integer.value[0] |
730 WM8776_HPZCEN | WM8776_UPDATE);
731 data->wm8776_regs[WM8776_HPLVOL] =
732 value->value.integer.value[0] | WM8776_HPZCEN;
733 data->wm8776_regs[WM8776_HPRVOL] =
734 value->value.integer.value[0] | WM8776_HPZCEN;
735 }
736 } else {
737 if (to_update & 1)
738 wm8776_write(chip, WM8776_HPLVOL,
739 value: value->value.integer.value[0] |
740 WM8776_HPZCEN |
741 ((to_update & 2) ? 0 : WM8776_UPDATE));
742 if (to_update & 2)
743 wm8776_write(chip, WM8776_HPRVOL,
744 value: value->value.integer.value[1] |
745 WM8776_HPZCEN | WM8776_UPDATE);
746 }
747 mutex_unlock(lock: &chip->mutex);
748 return to_update != 0;
749}
750
751static int wm8776_input_mux_get(struct snd_kcontrol *ctl,
752 struct snd_ctl_elem_value *value)
753{
754 struct oxygen *chip = ctl->private_data;
755 struct xonar_wm87x6 *data = chip->model_data;
756 unsigned int mux_bit = ctl->private_value;
757
758 value->value.integer.value[0] =
759 !!(data->wm8776_regs[WM8776_ADCMUX] & mux_bit);
760 return 0;
761}
762
763static int wm8776_input_mux_put(struct snd_kcontrol *ctl,
764 struct snd_ctl_elem_value *value)
765{
766 struct oxygen *chip = ctl->private_data;
767 struct xonar_wm87x6 *data = chip->model_data;
768 struct snd_kcontrol *other_ctl;
769 unsigned int mux_bit = ctl->private_value;
770 u16 reg;
771 int changed;
772
773 mutex_lock(&chip->mutex);
774 reg = data->wm8776_regs[WM8776_ADCMUX];
775 if (value->value.integer.value[0]) {
776 reg |= mux_bit;
777 /* line-in and mic-in are exclusive */
778 mux_bit ^= 3;
779 if (reg & mux_bit) {
780 reg &= ~mux_bit;
781 if (mux_bit == 1)
782 other_ctl = data->line_adcmux_control;
783 else
784 other_ctl = data->mic_adcmux_control;
785 snd_ctl_notify(card: chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
786 id: &other_ctl->id);
787 }
788 } else
789 reg &= ~mux_bit;
790 changed = reg != data->wm8776_regs[WM8776_ADCMUX];
791 if (changed) {
792 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
793 value: reg & 1 ? GPIO_DS_INPUT_ROUTE : 0,
794 GPIO_DS_INPUT_ROUTE);
795 wm8776_write(chip, WM8776_ADCMUX, value: reg);
796 }
797 mutex_unlock(lock: &chip->mutex);
798 return changed;
799}
800
801static int wm8776_input_vol_info(struct snd_kcontrol *ctl,
802 struct snd_ctl_elem_info *info)
803{
804 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
805 info->count = 2;
806 info->value.integer.min = 0xa5;
807 info->value.integer.max = 0xff;
808 return 0;
809}
810
811static int wm8776_input_vol_get(struct snd_kcontrol *ctl,
812 struct snd_ctl_elem_value *value)
813{
814 struct oxygen *chip = ctl->private_data;
815 struct xonar_wm87x6 *data = chip->model_data;
816
817 mutex_lock(&chip->mutex);
818 value->value.integer.value[0] =
819 data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK;
820 value->value.integer.value[1] =
821 data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK;
822 mutex_unlock(lock: &chip->mutex);
823 return 0;
824}
825
826static int wm8776_input_vol_put(struct snd_kcontrol *ctl,
827 struct snd_ctl_elem_value *value)
828{
829 struct oxygen *chip = ctl->private_data;
830 struct xonar_wm87x6 *data = chip->model_data;
831 int changed = 0;
832
833 mutex_lock(&chip->mutex);
834 changed = (value->value.integer.value[0] !=
835 (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) ||
836 (value->value.integer.value[1] !=
837 (data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK));
838 wm8776_write_cached(chip, WM8776_ADCLVOL,
839 value: value->value.integer.value[0] | WM8776_ZCA);
840 wm8776_write_cached(chip, WM8776_ADCRVOL,
841 value: value->value.integer.value[1] | WM8776_ZCA);
842 mutex_unlock(lock: &chip->mutex);
843 return changed;
844}
845
846static int wm8776_level_control_info(struct snd_kcontrol *ctl,
847 struct snd_ctl_elem_info *info)
848{
849 static const char *const names[3] = {
850 "None", "Peak Limiter", "Automatic Level Control"
851 };
852
853 return snd_ctl_enum_info(info, channels: 1, items: 3, names);
854}
855
856static int wm8776_level_control_get(struct snd_kcontrol *ctl,
857 struct snd_ctl_elem_value *value)
858{
859 struct oxygen *chip = ctl->private_data;
860 struct xonar_wm87x6 *data = chip->model_data;
861
862 if (!(data->wm8776_regs[WM8776_ALCCTRL2] & WM8776_LCEN))
863 value->value.enumerated.item[0] = 0;
864 else if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
865 WM8776_LCSEL_LIMITER)
866 value->value.enumerated.item[0] = 1;
867 else
868 value->value.enumerated.item[0] = 2;
869 return 0;
870}
871
872static void activate_control(struct oxygen *chip,
873 struct snd_kcontrol *ctl, unsigned int mode)
874{
875 unsigned int access;
876
877 if (ctl->private_value & mode)
878 access = 0;
879 else
880 access = SNDRV_CTL_ELEM_ACCESS_INACTIVE;
881 if ((ctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) != access) {
882 ctl->vd[0].access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
883 snd_ctl_notify(card: chip->card, SNDRV_CTL_EVENT_MASK_INFO, id: &ctl->id);
884 }
885}
886
887static int wm8776_level_control_put(struct snd_kcontrol *ctl,
888 struct snd_ctl_elem_value *value)
889{
890 struct oxygen *chip = ctl->private_data;
891 struct xonar_wm87x6 *data = chip->model_data;
892 unsigned int mode = 0, i;
893 u16 ctrl1, ctrl2;
894 int changed;
895
896 if (value->value.enumerated.item[0] >= 3)
897 return -EINVAL;
898 mutex_lock(&chip->mutex);
899 changed = value->value.enumerated.item[0] != ctl->private_value;
900 if (changed) {
901 ctl->private_value = value->value.enumerated.item[0];
902 ctrl1 = data->wm8776_regs[WM8776_ALCCTRL1];
903 ctrl2 = data->wm8776_regs[WM8776_ALCCTRL2];
904 switch (value->value.enumerated.item[0]) {
905 default:
906 wm8776_write_cached(chip, WM8776_ALCCTRL2,
907 value: ctrl2 & ~WM8776_LCEN);
908 break;
909 case 1:
910 wm8776_write_cached(chip, WM8776_ALCCTRL1,
911 value: (ctrl1 & ~WM8776_LCSEL_MASK) |
912 WM8776_LCSEL_LIMITER);
913 wm8776_write_cached(chip, WM8776_ALCCTRL2,
914 value: ctrl2 | WM8776_LCEN);
915 mode = LC_CONTROL_LIMITER;
916 break;
917 case 2:
918 wm8776_write_cached(chip, WM8776_ALCCTRL1,
919 value: (ctrl1 & ~WM8776_LCSEL_MASK) |
920 WM8776_LCSEL_ALC_STEREO);
921 wm8776_write_cached(chip, WM8776_ALCCTRL2,
922 value: ctrl2 | WM8776_LCEN);
923 mode = LC_CONTROL_ALC;
924 break;
925 }
926 for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i)
927 activate_control(chip, ctl: data->lc_controls[i], mode);
928 }
929 mutex_unlock(lock: &chip->mutex);
930 return changed;
931}
932
933static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
934{
935 static const char *const names[2] = {
936 "None", "High-pass Filter"
937 };
938
939 return snd_ctl_enum_info(info, channels: 1, items: 2, names);
940}
941
942static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
943{
944 struct oxygen *chip = ctl->private_data;
945 struct xonar_wm87x6 *data = chip->model_data;
946
947 value->value.enumerated.item[0] =
948 !(data->wm8776_regs[WM8776_ADCIFCTRL] & WM8776_ADCHPD);
949 return 0;
950}
951
952static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
953{
954 struct oxygen *chip = ctl->private_data;
955 struct xonar_wm87x6 *data = chip->model_data;
956 unsigned int reg;
957 int changed;
958
959 mutex_lock(&chip->mutex);
960 reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD;
961 if (!value->value.enumerated.item[0])
962 reg |= WM8776_ADCHPD;
963 changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL];
964 if (changed)
965 wm8776_write(chip, WM8776_ADCIFCTRL, value: reg);
966 mutex_unlock(lock: &chip->mutex);
967 return changed;
968}
969
970#define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \
971 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
972 .name = xname, \
973 .info = snd_ctl_boolean_mono_info, \
974 .get = wm8776_bit_switch_get, \
975 .put = wm8776_bit_switch_put, \
976 .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \
977}
978#define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \
979 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
980 .name = xname, \
981 .private_value = (initval) | ((min) << 8) | ((max) << 12) | \
982 ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags)
983#define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\
984 _WM8776_FIELD_CTL(xname " Capture Enum", \
985 reg, shift, init, min, max, mask, flags), \
986 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
987 SNDRV_CTL_ELEM_ACCESS_INACTIVE, \
988 .info = wm8776_field_enum_info, \
989 .get = wm8776_field_enum_get, \
990 .put = wm8776_field_enum_put, \
991}
992#define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \
993 _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \
994 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
995 SNDRV_CTL_ELEM_ACCESS_INACTIVE | \
996 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
997 .info = wm8776_field_volume_info, \
998 .get = wm8776_field_volume_get, \
999 .put = wm8776_field_volume_put, \
1000 .tlv = { .p = tlv_p }, \
1001}
1002
1003static const DECLARE_TLV_DB_SCALE(wm87x6_dac_db_scale, -6000, 50, 0);
1004static const DECLARE_TLV_DB_SCALE(wm8776_adc_db_scale, -2100, 50, 0);
1005static const DECLARE_TLV_DB_SCALE(wm8776_hp_db_scale, -6000, 100, 0);
1006static const DECLARE_TLV_DB_SCALE(wm8776_lct_db_scale, -1600, 100, 0);
1007static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_db_scale, 0, 400, 0);
1008static const DECLARE_TLV_DB_SCALE(wm8776_ngth_db_scale, -7800, 600, 0);
1009static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_db_scale, -1200, 100, 0);
1010static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_db_scale, -2100, 400, 0);
1011
1012static const struct snd_kcontrol_new ds_controls[] = {
1013 {
1014 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1015 .name = "Headphone Playback Volume",
1016 .info = wm8776_hp_vol_info,
1017 .get = wm8776_hp_vol_get,
1018 .put = wm8776_hp_vol_put,
1019 .tlv = { .p = wm8776_hp_db_scale },
1020 },
1021 WM8776_BIT_SWITCH("Headphone Playback Switch",
1022 WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
1023 {
1024 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1025 .name = "Input Capture Volume",
1026 .info = wm8776_input_vol_info,
1027 .get = wm8776_input_vol_get,
1028 .put = wm8776_input_vol_put,
1029 .tlv = { .p = wm8776_adc_db_scale },
1030 },
1031 {
1032 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1033 .name = "Line Capture Switch",
1034 .info = snd_ctl_boolean_mono_info,
1035 .get = wm8776_input_mux_get,
1036 .put = wm8776_input_mux_put,
1037 .private_value = 1 << 0,
1038 },
1039 {
1040 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1041 .name = "Mic Capture Switch",
1042 .info = snd_ctl_boolean_mono_info,
1043 .get = wm8776_input_mux_get,
1044 .put = wm8776_input_mux_put,
1045 .private_value = 1 << 1,
1046 },
1047 WM8776_BIT_SWITCH("Front Mic Capture Switch",
1048 WM8776_ADCMUX, 1 << 2, 0, 0),
1049 WM8776_BIT_SWITCH("Aux Capture Switch",
1050 WM8776_ADCMUX, 1 << 3, 0, 0),
1051 {
1052 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1053 .name = "ADC Filter Capture Enum",
1054 .info = hpf_info,
1055 .get = hpf_get,
1056 .put = hpf_put,
1057 },
1058 {
1059 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1060 .name = "Level Control Capture Enum",
1061 .info = wm8776_level_control_info,
1062 .get = wm8776_level_control_get,
1063 .put = wm8776_level_control_put,
1064 .private_value = 0,
1065 },
1066};
1067static const struct snd_kcontrol_new hdav_slim_controls[] = {
1068 {
1069 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1070 .name = "HDMI Playback Switch",
1071 .info = snd_ctl_boolean_mono_info,
1072 .get = xonar_gpio_bit_switch_get,
1073 .put = xonar_gpio_bit_switch_put,
1074 .private_value = GPIO_SLIM_HDMI_DISABLE | XONAR_GPIO_BIT_INVERT,
1075 },
1076 {
1077 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1078 .name = "Headphone Playback Volume",
1079 .info = wm8776_hp_vol_info,
1080 .get = wm8776_hp_vol_get,
1081 .put = wm8776_hp_vol_put,
1082 .tlv = { .p = wm8776_hp_db_scale },
1083 },
1084 WM8776_BIT_SWITCH("Headphone Playback Switch",
1085 WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
1086 {
1087 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1088 .name = "Input Capture Volume",
1089 .info = wm8776_input_vol_info,
1090 .get = wm8776_input_vol_get,
1091 .put = wm8776_input_vol_put,
1092 .tlv = { .p = wm8776_adc_db_scale },
1093 },
1094 WM8776_BIT_SWITCH("Mic Capture Switch",
1095 WM8776_ADCMUX, 1 << 0, 0, 0),
1096 WM8776_BIT_SWITCH("Aux Capture Switch",
1097 WM8776_ADCMUX, 1 << 1, 0, 0),
1098 {
1099 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1100 .name = "ADC Filter Capture Enum",
1101 .info = hpf_info,
1102 .get = hpf_get,
1103 .put = hpf_put,
1104 },
1105 {
1106 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1107 .name = "Level Control Capture Enum",
1108 .info = wm8776_level_control_info,
1109 .get = wm8776_level_control_get,
1110 .put = wm8776_level_control_put,
1111 .private_value = 0,
1112 },
1113};
1114static const struct snd_kcontrol_new lc_controls[] = {
1115 WM8776_FIELD_CTL_VOLUME("Limiter Threshold",
1116 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
1117 LC_CONTROL_LIMITER, wm8776_lct_db_scale),
1118 WM8776_FIELD_CTL_ENUM("Limiter Attack Time",
1119 WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
1120 LC_CONTROL_LIMITER),
1121 WM8776_FIELD_CTL_ENUM("Limiter Decay Time",
1122 WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
1123 LC_CONTROL_LIMITER),
1124 WM8776_FIELD_CTL_ENUM("Limiter Transient Window",
1125 WM8776_LIMITER, 4, 2, 0, 7, 0x7,
1126 LC_CONTROL_LIMITER),
1127 WM8776_FIELD_CTL_VOLUME("Limiter Maximum Attenuation",
1128 WM8776_LIMITER, 0, 6, 3, 12, 0xf,
1129 LC_CONTROL_LIMITER,
1130 wm8776_maxatten_lim_db_scale),
1131 WM8776_FIELD_CTL_VOLUME("ALC Target Level",
1132 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
1133 LC_CONTROL_ALC, wm8776_lct_db_scale),
1134 WM8776_FIELD_CTL_ENUM("ALC Attack Time",
1135 WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
1136 LC_CONTROL_ALC),
1137 WM8776_FIELD_CTL_ENUM("ALC Decay Time",
1138 WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
1139 LC_CONTROL_ALC),
1140 WM8776_FIELD_CTL_VOLUME("ALC Maximum Gain",
1141 WM8776_ALCCTRL1, 4, 7, 1, 7, 0x7,
1142 LC_CONTROL_ALC, wm8776_maxgain_db_scale),
1143 WM8776_FIELD_CTL_VOLUME("ALC Maximum Attenuation",
1144 WM8776_LIMITER, 0, 10, 10, 15, 0xf,
1145 LC_CONTROL_ALC, wm8776_maxatten_alc_db_scale),
1146 WM8776_FIELD_CTL_ENUM("ALC Hold Time",
1147 WM8776_ALCCTRL2, 0, 0, 0, 15, 0xf,
1148 LC_CONTROL_ALC),
1149 WM8776_BIT_SWITCH("Noise Gate Capture Switch",
1150 WM8776_NOISEGATE, WM8776_NGAT, 0,
1151 LC_CONTROL_ALC),
1152 WM8776_FIELD_CTL_VOLUME("Noise Gate Threshold",
1153 WM8776_NOISEGATE, 2, 0, 0, 7, 0x7,
1154 LC_CONTROL_ALC, wm8776_ngth_db_scale),
1155};
1156
1157static int add_lc_controls(struct oxygen *chip)
1158{
1159 struct xonar_wm87x6 *data = chip->model_data;
1160 unsigned int i;
1161 struct snd_kcontrol *ctl;
1162 int err;
1163
1164 BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
1165 for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
1166 ctl = snd_ctl_new1(kcontrolnew: &lc_controls[i], private_data: chip);
1167 if (!ctl)
1168 return -ENOMEM;
1169 err = snd_ctl_add(card: chip->card, kcontrol: ctl);
1170 if (err < 0)
1171 return err;
1172 data->lc_controls[i] = ctl;
1173 }
1174 return 0;
1175}
1176
1177static int xonar_ds_mixer_init(struct oxygen *chip)
1178{
1179 struct xonar_wm87x6 *data = chip->model_data;
1180 unsigned int i;
1181 struct snd_kcontrol *ctl;
1182 int err;
1183
1184 for (i = 0; i < ARRAY_SIZE(ds_controls); ++i) {
1185 ctl = snd_ctl_new1(kcontrolnew: &ds_controls[i], private_data: chip);
1186 if (!ctl)
1187 return -ENOMEM;
1188 err = snd_ctl_add(card: chip->card, kcontrol: ctl);
1189 if (err < 0)
1190 return err;
1191 if (!strcmp(ctl->id.name, "Line Capture Switch"))
1192 data->line_adcmux_control = ctl;
1193 else if (!strcmp(ctl->id.name, "Mic Capture Switch"))
1194 data->mic_adcmux_control = ctl;
1195 }
1196 if (!data->line_adcmux_control || !data->mic_adcmux_control)
1197 return -ENXIO;
1198
1199 return add_lc_controls(chip);
1200}
1201
1202static int xonar_hdav_slim_mixer_init(struct oxygen *chip)
1203{
1204 unsigned int i;
1205 struct snd_kcontrol *ctl;
1206 int err;
1207
1208 for (i = 0; i < ARRAY_SIZE(hdav_slim_controls); ++i) {
1209 ctl = snd_ctl_new1(kcontrolnew: &hdav_slim_controls[i], private_data: chip);
1210 if (!ctl)
1211 return -ENOMEM;
1212 err = snd_ctl_add(card: chip->card, kcontrol: ctl);
1213 if (err < 0)
1214 return err;
1215 }
1216
1217 return add_lc_controls(chip);
1218}
1219
1220static void dump_wm8776_registers(struct oxygen *chip,
1221 struct snd_info_buffer *buffer)
1222{
1223 struct xonar_wm87x6 *data = chip->model_data;
1224 unsigned int i;
1225
1226 snd_iprintf(buffer, "\nWM8776:\n00:");
1227 for (i = 0; i < 0x10; ++i)
1228 snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
1229 snd_iprintf(buffer, "\n10:");
1230 for (i = 0x10; i < 0x17; ++i)
1231 snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
1232 snd_iprintf(buffer, "\n");
1233}
1234
1235static void dump_wm87x6_registers(struct oxygen *chip,
1236 struct snd_info_buffer *buffer)
1237{
1238 struct xonar_wm87x6 *data = chip->model_data;
1239 unsigned int i;
1240
1241 dump_wm8776_registers(chip, buffer);
1242 snd_iprintf(buffer, "\nWM8766:\n00:");
1243 for (i = 0; i < 0x10; ++i)
1244 snd_iprintf(buffer, " %03x", data->wm8766_regs[i]);
1245 snd_iprintf(buffer, "\n");
1246}
1247
1248static const struct oxygen_model model_xonar_ds = {
1249 .longname = "Asus Virtuoso 66",
1250 .chip = "AV200",
1251 .init = xonar_ds_init,
1252 .mixer_init = xonar_ds_mixer_init,
1253 .cleanup = xonar_ds_cleanup,
1254 .suspend = xonar_ds_suspend,
1255 .resume = xonar_ds_resume,
1256 .pcm_hardware_filter = wm8776_adc_hardware_filter,
1257 .set_dac_params = set_wm87x6_dac_params,
1258 .set_adc_params = set_wm8776_adc_params,
1259 .update_dac_volume = update_wm87x6_volume,
1260 .update_dac_mute = update_wm87x6_mute,
1261 .update_center_lfe_mix = update_wm8766_center_lfe_mix,
1262 .gpio_changed = xonar_ds_gpio_changed,
1263 .dump_registers = dump_wm87x6_registers,
1264 .dac_tlv = wm87x6_dac_db_scale,
1265 .model_data_size = sizeof(struct xonar_wm87x6),
1266 .device_config = PLAYBACK_0_TO_I2S |
1267 PLAYBACK_1_TO_SPDIF |
1268 CAPTURE_0_FROM_I2S_1 |
1269 CAPTURE_1_FROM_SPDIF,
1270 .dac_channels_pcm = 8,
1271 .dac_channels_mixer = 8,
1272 .dac_volume_min = 255 - 2*60,
1273 .dac_volume_max = 255,
1274 .function_flags = OXYGEN_FUNCTION_SPI,
1275 .dac_mclks = OXYGEN_MCLKS(256, 256, 128),
1276 .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
1277 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1278 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1279};
1280
1281static const struct oxygen_model model_xonar_hdav_slim = {
1282 .shortname = "Xonar HDAV1.3 Slim",
1283 .longname = "Asus Virtuoso 200",
1284 .chip = "AV200",
1285 .init = xonar_hdav_slim_init,
1286 .mixer_init = xonar_hdav_slim_mixer_init,
1287 .cleanup = xonar_hdav_slim_cleanup,
1288 .suspend = xonar_hdav_slim_suspend,
1289 .resume = xonar_hdav_slim_resume,
1290 .pcm_hardware_filter = xonar_hdav_slim_hardware_filter,
1291 .set_dac_params = set_hdav_slim_dac_params,
1292 .set_adc_params = set_wm8776_adc_params,
1293 .update_dac_volume = update_wm8776_volume,
1294 .update_dac_mute = update_wm8776_mute,
1295 .uart_input = xonar_hdmi_uart_input,
1296 .dump_registers = dump_wm8776_registers,
1297 .dac_tlv = wm87x6_dac_db_scale,
1298 .model_data_size = sizeof(struct xonar_wm87x6),
1299 .device_config = PLAYBACK_0_TO_I2S |
1300 PLAYBACK_1_TO_SPDIF |
1301 CAPTURE_0_FROM_I2S_1 |
1302 CAPTURE_1_FROM_SPDIF,
1303 .dac_channels_pcm = 8,
1304 .dac_channels_mixer = 2,
1305 .dac_volume_min = 255 - 2*60,
1306 .dac_volume_max = 255,
1307 .function_flags = OXYGEN_FUNCTION_2WIRE,
1308 .dac_mclks = OXYGEN_MCLKS(256, 256, 128),
1309 .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
1310 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1311 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1312};
1313
1314int get_xonar_wm87x6_model(struct oxygen *chip,
1315 const struct pci_device_id *id)
1316{
1317 switch (id->subdevice) {
1318 case 0x838e:
1319 chip->model = model_xonar_ds;
1320 chip->model.shortname = "Xonar DS";
1321 break;
1322 case 0x8522:
1323 chip->model = model_xonar_ds;
1324 chip->model.shortname = "Xonar DSX";
1325 break;
1326 case 0x835e:
1327 chip->model = model_xonar_hdav_slim;
1328 break;
1329 default:
1330 return -EINVAL;
1331 }
1332 return 0;
1333}
1334

source code of linux/sound/pci/oxygen/xonar_wm87x6.c