File Index
Files and directories
Sign in
FILE

xonar_wm87x6.c

File preview with syntax highlighting.

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