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