162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * card driver for models with PCM1796 DACs (Xonar D2/D2X/HDAV1.3/ST/STX)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * Xonar D2/D2X
1062306a36Sopenharmony_ci * ------------
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * CMI8788:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *   SPI 0 -> 1st PCM1796 (front)
1562306a36Sopenharmony_ci *   SPI 1 -> 2nd PCM1796 (surround)
1662306a36Sopenharmony_ci *   SPI 2 -> 3rd PCM1796 (center/LFE)
1762306a36Sopenharmony_ci *   SPI 4 -> 4th PCM1796 (back)
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *   GPIO 2 -> M0 of CS5381
2062306a36Sopenharmony_ci *   GPIO 3 -> M1 of CS5381
2162306a36Sopenharmony_ci *   GPIO 5 <- external power present (D2X only)
2262306a36Sopenharmony_ci *   GPIO 7 -> ALT
2362306a36Sopenharmony_ci *   GPIO 8 -> enable output to speakers
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * CM9780:
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci *   LINE_OUT -> input of ADC
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci *   AUX_IN   <- aux
3062306a36Sopenharmony_ci *   VIDEO_IN <- CD
3162306a36Sopenharmony_ci *   FMIC_IN  <- mic
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci *   GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * Xonar HDAV1.3 (Deluxe)
3862306a36Sopenharmony_ci * ----------------------
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * CMI8788:
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci *   I²C <-> PCM1796 (addr 1001100) (front)
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci *   GPI 0 <- external power present
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci *   GPIO 0 -> enable HDMI (0) or speaker (1) output
4762306a36Sopenharmony_ci *   GPIO 2 -> M0 of CS5381
4862306a36Sopenharmony_ci *   GPIO 3 -> M1 of CS5381
4962306a36Sopenharmony_ci *   GPIO 4 <- daughterboard detection
5062306a36Sopenharmony_ci *   GPIO 5 <- daughterboard detection
5162306a36Sopenharmony_ci *   GPIO 6 -> ?
5262306a36Sopenharmony_ci *   GPIO 7 -> ?
5362306a36Sopenharmony_ci *   GPIO 8 -> route input jack to line-in (0) or mic-in (1)
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci *   UART <-> HDMI controller
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * CM9780:
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci *   LINE_OUT -> input of ADC
6062306a36Sopenharmony_ci *
6162306a36Sopenharmony_ci *   AUX_IN <- aux
6262306a36Sopenharmony_ci *   CD_IN  <- CD
6362306a36Sopenharmony_ci *   MIC_IN <- mic
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci *   GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
6662306a36Sopenharmony_ci *
6762306a36Sopenharmony_ci * no daughterboard
6862306a36Sopenharmony_ci * ----------------
6962306a36Sopenharmony_ci *
7062306a36Sopenharmony_ci *   GPIO 4 <- 1
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * H6 daughterboard
7362306a36Sopenharmony_ci * ----------------
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci *   GPIO 4 <- 0
7662306a36Sopenharmony_ci *   GPIO 5 <- 0
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci *   I²C <-> PCM1796 (addr 1001101) (surround)
7962306a36Sopenharmony_ci *       <-> PCM1796 (addr 1001110) (center/LFE)
8062306a36Sopenharmony_ci *       <-> PCM1796 (addr 1001111) (back)
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * unknown daughterboard
8362306a36Sopenharmony_ci * ---------------------
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci *   GPIO 4 <- 0
8662306a36Sopenharmony_ci *   GPIO 5 <- 1
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci *   I²C <-> CS4362A (addr 0011000) (surround, center/LFE, back)
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci * Xonar Essence ST (Deluxe)/STX (II)
9362306a36Sopenharmony_ci * ----------------------------------
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * CMI8788:
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci *   I²C <-> PCM1792A (addr 1001100)
9862306a36Sopenharmony_ci *       <-> CS2000 (addr 1001110) (ST only)
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci *   ADC1 MCLK -> REF_CLK of CS2000 (ST only)
10162306a36Sopenharmony_ci *
10262306a36Sopenharmony_ci *   GPI 0 <- external power present (STX only)
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci *   GPIO 0 -> enable output to speakers
10562306a36Sopenharmony_ci *   GPIO 1 -> route HP to front panel (0) or rear jack (1)
10662306a36Sopenharmony_ci *   GPIO 2 -> M0 of CS5381
10762306a36Sopenharmony_ci *   GPIO 3 -> M1 of CS5381
10862306a36Sopenharmony_ci *   GPIO 4 <- daughterboard detection
10962306a36Sopenharmony_ci *   GPIO 5 <- daughterboard detection
11062306a36Sopenharmony_ci *   GPIO 6 -> ?
11162306a36Sopenharmony_ci *   GPIO 7 -> route output to speaker jacks (0) or HP (1)
11262306a36Sopenharmony_ci *   GPIO 8 -> route input jack to line-in (0) or mic-in (1)
11362306a36Sopenharmony_ci *
11462306a36Sopenharmony_ci * PCM1792A:
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci *   SCK <- CLK_OUT of CS2000 (ST only)
11762306a36Sopenharmony_ci *
11862306a36Sopenharmony_ci * CM9780:
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci *   LINE_OUT -> input of ADC
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci *   AUX_IN <- aux
12362306a36Sopenharmony_ci *   MIC_IN <- mic
12462306a36Sopenharmony_ci *
12562306a36Sopenharmony_ci *   GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * H6 daughterboard
12862306a36Sopenharmony_ci * ----------------
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * GPIO 4 <- 0
13162306a36Sopenharmony_ci * GPIO 5 <- 0
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/*
13562306a36Sopenharmony_ci * Xonar Xense
13662306a36Sopenharmony_ci * -----------
13762306a36Sopenharmony_ci *
13862306a36Sopenharmony_ci * CMI8788:
13962306a36Sopenharmony_ci *
14062306a36Sopenharmony_ci *   I²C <-> PCM1796 (addr 1001100) (front)
14162306a36Sopenharmony_ci *       <-> CS4362A (addr 0011000) (surround, center/LFE, back)
14262306a36Sopenharmony_ci *       <-> CS2000 (addr 1001110)
14362306a36Sopenharmony_ci *
14462306a36Sopenharmony_ci *   ADC1 MCLK -> REF_CLK of CS2000
14562306a36Sopenharmony_ci *
14662306a36Sopenharmony_ci *   GPI 0 <- external power present
14762306a36Sopenharmony_ci *
14862306a36Sopenharmony_ci *   GPIO 0 -> enable output
14962306a36Sopenharmony_ci *   GPIO 1 -> route HP to front panel (0) or rear jack (1)
15062306a36Sopenharmony_ci *   GPIO 2 -> M0 of CS5381
15162306a36Sopenharmony_ci *   GPIO 3 -> M1 of CS5381
15262306a36Sopenharmony_ci *   GPIO 4 -> enable output
15362306a36Sopenharmony_ci *   GPIO 5 -> enable output
15462306a36Sopenharmony_ci *   GPIO 6 -> ?
15562306a36Sopenharmony_ci *   GPIO 7 -> route output to HP (0) or speaker (1)
15662306a36Sopenharmony_ci *   GPIO 8 -> route input jack to mic-in (0) or line-in (1)
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * CM9780:
15962306a36Sopenharmony_ci *
16062306a36Sopenharmony_ci *   LINE_OUT -> input of ADC
16162306a36Sopenharmony_ci *
16262306a36Sopenharmony_ci *   AUX_IN   <- aux
16362306a36Sopenharmony_ci *   VIDEO_IN <- ?
16462306a36Sopenharmony_ci *   FMIC_IN  <- mic
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci *   GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
16762306a36Sopenharmony_ci *   GPO 1 -> route mic-in from input jack (0) or front panel header (1)
16862306a36Sopenharmony_ci */
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#include <linux/pci.h>
17162306a36Sopenharmony_ci#include <linux/delay.h>
17262306a36Sopenharmony_ci#include <linux/mutex.h>
17362306a36Sopenharmony_ci#include <sound/ac97_codec.h>
17462306a36Sopenharmony_ci#include <sound/control.h>
17562306a36Sopenharmony_ci#include <sound/core.h>
17662306a36Sopenharmony_ci#include <sound/info.h>
17762306a36Sopenharmony_ci#include <sound/pcm.h>
17862306a36Sopenharmony_ci#include <sound/pcm_params.h>
17962306a36Sopenharmony_ci#include <sound/tlv.h>
18062306a36Sopenharmony_ci#include "xonar.h"
18162306a36Sopenharmony_ci#include "cm9780.h"
18262306a36Sopenharmony_ci#include "pcm1796.h"
18362306a36Sopenharmony_ci#include "cs2000.h"
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci#define GPIO_D2X_EXT_POWER	0x0020
18762306a36Sopenharmony_ci#define GPIO_D2_ALT		0x0080
18862306a36Sopenharmony_ci#define GPIO_D2_OUTPUT_ENABLE	0x0100
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci#define GPI_EXT_POWER		0x01
19162306a36Sopenharmony_ci#define GPIO_INPUT_ROUTE	0x0100
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci#define GPIO_HDAV_OUTPUT_ENABLE	0x0001
19462306a36Sopenharmony_ci#define GPIO_HDAV_MAGIC		0x00c0
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci#define GPIO_DB_MASK		0x0030
19762306a36Sopenharmony_ci#define GPIO_DB_H6		0x0000
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#define GPIO_ST_OUTPUT_ENABLE	0x0001
20062306a36Sopenharmony_ci#define GPIO_ST_HP_REAR		0x0002
20162306a36Sopenharmony_ci#define GPIO_ST_MAGIC		0x0040
20262306a36Sopenharmony_ci#define GPIO_ST_HP		0x0080
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci#define GPIO_XENSE_OUTPUT_ENABLE	(0x0001 | 0x0010 | 0x0020)
20562306a36Sopenharmony_ci#define GPIO_XENSE_SPEAKERS		0x0080
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci#define I2C_DEVICE_PCM1796(i)	(0x98 + ((i) << 1))	/* 10011, ii, /W=0 */
20862306a36Sopenharmony_ci#define I2C_DEVICE_CS2000	0x9c			/* 100111, 0, /W=0 */
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci#define PCM1796_REG_BASE	16
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistruct xonar_pcm179x {
21462306a36Sopenharmony_ci	struct xonar_generic generic;
21562306a36Sopenharmony_ci	unsigned int dacs;
21662306a36Sopenharmony_ci	u8 pcm1796_regs[4][5];
21762306a36Sopenharmony_ci	unsigned int current_rate;
21862306a36Sopenharmony_ci	bool h6;
21962306a36Sopenharmony_ci	bool hp_active;
22062306a36Sopenharmony_ci	s8 hp_gain_offset;
22162306a36Sopenharmony_ci	bool has_cs2000;
22262306a36Sopenharmony_ci	u8 cs2000_regs[0x1f];
22362306a36Sopenharmony_ci	bool broken_i2c;
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistruct xonar_hdav {
22762306a36Sopenharmony_ci	struct xonar_pcm179x pcm179x;
22862306a36Sopenharmony_ci	struct xonar_hdmi hdmi;
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
23362306a36Sopenharmony_ci				     u8 reg, u8 value)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	/* maps ALSA channel pair number to SPI output */
23662306a36Sopenharmony_ci	static const u8 codec_map[4] = {
23762306a36Sopenharmony_ci		0, 1, 2, 4
23862306a36Sopenharmony_ci	};
23962306a36Sopenharmony_ci	oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER  |
24062306a36Sopenharmony_ci			 OXYGEN_SPI_DATA_LENGTH_2 |
24162306a36Sopenharmony_ci			 OXYGEN_SPI_CLOCK_160 |
24262306a36Sopenharmony_ci			 (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
24362306a36Sopenharmony_ci			 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
24462306a36Sopenharmony_ci			 (reg << 8) | value);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
24862306a36Sopenharmony_ci				     u8 reg, u8 value)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic void pcm1796_write(struct oxygen *chip, unsigned int codec,
25462306a36Sopenharmony_ci			  u8 reg, u8 value)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
25962306a36Sopenharmony_ci	    OXYGEN_FUNCTION_SPI)
26062306a36Sopenharmony_ci		pcm1796_write_spi(chip, codec, reg, value);
26162306a36Sopenharmony_ci	else
26262306a36Sopenharmony_ci		pcm1796_write_i2c(chip, codec, reg, value);
26362306a36Sopenharmony_ci	if ((unsigned int)(reg - PCM1796_REG_BASE)
26462306a36Sopenharmony_ci	    < ARRAY_SIZE(data->pcm1796_regs[codec]))
26562306a36Sopenharmony_ci		data->pcm1796_regs[codec][reg - PCM1796_REG_BASE] = value;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic void pcm1796_write_cached(struct oxygen *chip, unsigned int codec,
26962306a36Sopenharmony_ci				 u8 reg, u8 value)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (value != data->pcm1796_regs[codec][reg - PCM1796_REG_BASE])
27462306a36Sopenharmony_ci		pcm1796_write(chip, codec, reg, value);
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void cs2000_write(struct oxygen *chip, u8 reg, u8 value)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value);
28262306a36Sopenharmony_ci	data->cs2000_regs[reg] = value;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (value != data->cs2000_regs[reg])
29062306a36Sopenharmony_ci		cs2000_write(chip, reg, value);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic void pcm1796_registers_init(struct oxygen *chip)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
29662306a36Sopenharmony_ci	unsigned int i;
29762306a36Sopenharmony_ci	s8 gain_offset;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	msleep(1);
30062306a36Sopenharmony_ci	gain_offset = data->hp_active ? data->hp_gain_offset : 0;
30162306a36Sopenharmony_ci	for (i = 0; i < data->dacs; ++i) {
30262306a36Sopenharmony_ci		/* set ATLD before ATL/ATR */
30362306a36Sopenharmony_ci		pcm1796_write(chip, i, 18,
30462306a36Sopenharmony_ci			      data->pcm1796_regs[0][18 - PCM1796_REG_BASE]);
30562306a36Sopenharmony_ci		pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]
30662306a36Sopenharmony_ci			      + gain_offset);
30762306a36Sopenharmony_ci		pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]
30862306a36Sopenharmony_ci			      + gain_offset);
30962306a36Sopenharmony_ci		pcm1796_write(chip, i, 19,
31062306a36Sopenharmony_ci			      data->pcm1796_regs[0][19 - PCM1796_REG_BASE]);
31162306a36Sopenharmony_ci		pcm1796_write(chip, i, 20,
31262306a36Sopenharmony_ci			      data->pcm1796_regs[0][20 - PCM1796_REG_BASE]);
31362306a36Sopenharmony_ci		pcm1796_write(chip, i, 21, 0);
31462306a36Sopenharmony_ci		gain_offset = 0;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic void pcm1796_init(struct oxygen *chip)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	data->pcm1796_regs[0][18 - PCM1796_REG_BASE] =
32362306a36Sopenharmony_ci		PCM1796_FMT_24_I2S | PCM1796_ATLD;
32462306a36Sopenharmony_ci	if (!data->broken_i2c)
32562306a36Sopenharmony_ci		data->pcm1796_regs[0][18 - PCM1796_REG_BASE] |= PCM1796_MUTE;
32662306a36Sopenharmony_ci	data->pcm1796_regs[0][19 - PCM1796_REG_BASE] =
32762306a36Sopenharmony_ci		PCM1796_FLT_SHARP | PCM1796_ATS_1;
32862306a36Sopenharmony_ci	data->pcm1796_regs[0][20 - PCM1796_REG_BASE] =
32962306a36Sopenharmony_ci		data->h6 ? PCM1796_OS_64 : PCM1796_OS_128;
33062306a36Sopenharmony_ci	pcm1796_registers_init(chip);
33162306a36Sopenharmony_ci	data->current_rate = 48000;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic void xonar_d2_init(struct oxygen *chip)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	data->generic.anti_pop_delay = 300;
33962306a36Sopenharmony_ci	data->generic.output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
34062306a36Sopenharmony_ci	data->dacs = 4;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	pcm1796_init(chip);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT);
34562306a36Sopenharmony_ci	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	xonar_init_cs53x1(chip);
35062306a36Sopenharmony_ci	xonar_enable_output(chip);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	snd_component_add(chip->card, "PCM1796");
35362306a36Sopenharmony_ci	snd_component_add(chip->card, "CS5381");
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void xonar_d2x_init(struct oxygen *chip)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	data->generic.ext_power_reg = OXYGEN_GPIO_DATA;
36162306a36Sopenharmony_ci	data->generic.ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
36262306a36Sopenharmony_ci	data->generic.ext_power_bit = GPIO_D2X_EXT_POWER;
36362306a36Sopenharmony_ci	oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
36462306a36Sopenharmony_ci	xonar_init_ext_power(chip);
36562306a36Sopenharmony_ci	xonar_d2_init(chip);
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic void xonar_hdav_init(struct oxygen *chip)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct xonar_hdav *data = chip->model_data;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
37362306a36Sopenharmony_ci		       OXYGEN_2WIRE_LENGTH_8 |
37462306a36Sopenharmony_ci		       OXYGEN_2WIRE_INTERRUPT_MASK |
37562306a36Sopenharmony_ci		       OXYGEN_2WIRE_SPEED_STANDARD);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	data->pcm179x.generic.anti_pop_delay = 100;
37862306a36Sopenharmony_ci	data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE;
37962306a36Sopenharmony_ci	data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA;
38062306a36Sopenharmony_ci	data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
38162306a36Sopenharmony_ci	data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER;
38262306a36Sopenharmony_ci	data->pcm179x.dacs = chip->model.dac_channels_mixer / 2;
38362306a36Sopenharmony_ci	data->pcm179x.h6 = chip->model.dac_channels_mixer > 2;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	pcm1796_init(chip);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
38862306a36Sopenharmony_ci			  GPIO_HDAV_MAGIC | GPIO_INPUT_ROUTE);
38962306a36Sopenharmony_ci	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	xonar_init_cs53x1(chip);
39262306a36Sopenharmony_ci	xonar_init_ext_power(chip);
39362306a36Sopenharmony_ci	xonar_hdmi_init(chip, &data->hdmi);
39462306a36Sopenharmony_ci	xonar_enable_output(chip);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	snd_component_add(chip->card, "PCM1796");
39762306a36Sopenharmony_ci	snd_component_add(chip->card, "CS5381");
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic void xonar_st_init_i2c(struct oxygen *chip)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
40362306a36Sopenharmony_ci		       OXYGEN_2WIRE_LENGTH_8 |
40462306a36Sopenharmony_ci		       OXYGEN_2WIRE_INTERRUPT_MASK |
40562306a36Sopenharmony_ci		       OXYGEN_2WIRE_SPEED_STANDARD);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void xonar_st_init_common(struct oxygen *chip)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
41362306a36Sopenharmony_ci	data->dacs = chip->model.dac_channels_mixer / 2;
41462306a36Sopenharmony_ci	data->h6 = chip->model.dac_channels_mixer > 2;
41562306a36Sopenharmony_ci	data->hp_gain_offset = 2*-18;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	pcm1796_init(chip);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
42062306a36Sopenharmony_ci			  GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
42162306a36Sopenharmony_ci			  GPIO_ST_MAGIC | GPIO_ST_HP);
42262306a36Sopenharmony_ci	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
42362306a36Sopenharmony_ci			    GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	xonar_init_cs53x1(chip);
42662306a36Sopenharmony_ci	xonar_enable_output(chip);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	snd_component_add(chip->card, "PCM1792A");
42962306a36Sopenharmony_ci	snd_component_add(chip->card, "CS5381");
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic void cs2000_registers_init(struct oxygen *chip)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_FREEZE);
43762306a36Sopenharmony_ci	cs2000_write(chip, CS2000_DEV_CTRL, 0);
43862306a36Sopenharmony_ci	cs2000_write(chip, CS2000_DEV_CFG_1,
43962306a36Sopenharmony_ci		     CS2000_R_MOD_SEL_1 |
44062306a36Sopenharmony_ci		     (0 << CS2000_R_SEL_SHIFT) |
44162306a36Sopenharmony_ci		     CS2000_AUX_OUT_SRC_REF_CLK |
44262306a36Sopenharmony_ci		     CS2000_EN_DEV_CFG_1);
44362306a36Sopenharmony_ci	cs2000_write(chip, CS2000_DEV_CFG_2,
44462306a36Sopenharmony_ci		     (0 << CS2000_LOCK_CLK_SHIFT) |
44562306a36Sopenharmony_ci		     CS2000_FRAC_N_SRC_STATIC);
44662306a36Sopenharmony_ci	cs2000_write(chip, CS2000_RATIO_0 + 0, 0x00); /* 1.0 */
44762306a36Sopenharmony_ci	cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10);
44862306a36Sopenharmony_ci	cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00);
44962306a36Sopenharmony_ci	cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00);
45062306a36Sopenharmony_ci	cs2000_write(chip, CS2000_FUN_CFG_1,
45162306a36Sopenharmony_ci		     data->cs2000_regs[CS2000_FUN_CFG_1]);
45262306a36Sopenharmony_ci	cs2000_write(chip, CS2000_FUN_CFG_2, 0);
45362306a36Sopenharmony_ci	cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2);
45462306a36Sopenharmony_ci	msleep(3); /* PLL lock delay */
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic void xonar_st_init(struct oxygen *chip)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	data->generic.anti_pop_delay = 100;
46262306a36Sopenharmony_ci	data->h6 = chip->model.dac_channels_mixer > 2;
46362306a36Sopenharmony_ci	data->has_cs2000 = true;
46462306a36Sopenharmony_ci	data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;
46562306a36Sopenharmony_ci	data->broken_i2c = true;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
46862306a36Sopenharmony_ci		       OXYGEN_RATE_48000 |
46962306a36Sopenharmony_ci		       OXYGEN_I2S_FORMAT_I2S |
47062306a36Sopenharmony_ci		       OXYGEN_I2S_MCLK(data->h6 ? MCLK_256 : MCLK_512) |
47162306a36Sopenharmony_ci		       OXYGEN_I2S_BITS_16 |
47262306a36Sopenharmony_ci		       OXYGEN_I2S_MASTER |
47362306a36Sopenharmony_ci		       OXYGEN_I2S_BCLK_64);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	xonar_st_init_i2c(chip);
47662306a36Sopenharmony_ci	cs2000_registers_init(chip);
47762306a36Sopenharmony_ci	xonar_st_init_common(chip);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	snd_component_add(chip->card, "CS2000");
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic void xonar_stx_init(struct oxygen *chip)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	xonar_st_init_i2c(chip);
48762306a36Sopenharmony_ci	data->generic.anti_pop_delay = 800;
48862306a36Sopenharmony_ci	data->generic.ext_power_reg = OXYGEN_GPI_DATA;
48962306a36Sopenharmony_ci	data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
49062306a36Sopenharmony_ci	data->generic.ext_power_bit = GPI_EXT_POWER;
49162306a36Sopenharmony_ci	xonar_init_ext_power(chip);
49262306a36Sopenharmony_ci	xonar_st_init_common(chip);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic void xonar_xense_init(struct oxygen *chip)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	data->generic.ext_power_reg = OXYGEN_GPI_DATA;
50062306a36Sopenharmony_ci	data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
50162306a36Sopenharmony_ci	data->generic.ext_power_bit = GPI_EXT_POWER;
50262306a36Sopenharmony_ci	xonar_init_ext_power(chip);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	data->generic.anti_pop_delay = 100;
50562306a36Sopenharmony_ci	data->has_cs2000 = true;
50662306a36Sopenharmony_ci	data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
50962306a36Sopenharmony_ci		OXYGEN_RATE_48000 |
51062306a36Sopenharmony_ci		OXYGEN_I2S_FORMAT_I2S |
51162306a36Sopenharmony_ci		OXYGEN_I2S_MCLK(MCLK_512) |
51262306a36Sopenharmony_ci		OXYGEN_I2S_BITS_16 |
51362306a36Sopenharmony_ci		OXYGEN_I2S_MASTER |
51462306a36Sopenharmony_ci		OXYGEN_I2S_BCLK_64);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	xonar_st_init_i2c(chip);
51762306a36Sopenharmony_ci	cs2000_registers_init(chip);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	data->generic.output_enable_bit = GPIO_XENSE_OUTPUT_ENABLE;
52062306a36Sopenharmony_ci	data->dacs = 1;
52162306a36Sopenharmony_ci	data->hp_gain_offset = 2*-18;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	pcm1796_init(chip);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
52662306a36Sopenharmony_ci		GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
52762306a36Sopenharmony_ci		GPIO_ST_MAGIC | GPIO_XENSE_SPEAKERS);
52862306a36Sopenharmony_ci	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
52962306a36Sopenharmony_ci		GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
53062306a36Sopenharmony_ci		GPIO_XENSE_SPEAKERS);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	xonar_init_cs53x1(chip);
53362306a36Sopenharmony_ci	xonar_enable_output(chip);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	snd_component_add(chip->card, "PCM1796");
53662306a36Sopenharmony_ci	snd_component_add(chip->card, "CS5381");
53762306a36Sopenharmony_ci	snd_component_add(chip->card, "CS2000");
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic void xonar_d2_cleanup(struct oxygen *chip)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	xonar_disable_output(chip);
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic void xonar_hdav_cleanup(struct oxygen *chip)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	xonar_hdmi_cleanup(chip);
54862306a36Sopenharmony_ci	xonar_disable_output(chip);
54962306a36Sopenharmony_ci	msleep(2);
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic void xonar_st_cleanup(struct oxygen *chip)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	xonar_disable_output(chip);
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic void xonar_d2_suspend(struct oxygen *chip)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	xonar_d2_cleanup(chip);
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic void xonar_hdav_suspend(struct oxygen *chip)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	xonar_hdav_cleanup(chip);
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic void xonar_st_suspend(struct oxygen *chip)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	xonar_st_cleanup(chip);
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic void xonar_d2_resume(struct oxygen *chip)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	pcm1796_registers_init(chip);
57562306a36Sopenharmony_ci	xonar_enable_output(chip);
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic void xonar_hdav_resume(struct oxygen *chip)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct xonar_hdav *data = chip->model_data;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	pcm1796_registers_init(chip);
58362306a36Sopenharmony_ci	xonar_hdmi_resume(chip, &data->hdmi);
58462306a36Sopenharmony_ci	xonar_enable_output(chip);
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic void xonar_stx_resume(struct oxygen *chip)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	pcm1796_registers_init(chip);
59062306a36Sopenharmony_ci	xonar_enable_output(chip);
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic void xonar_st_resume(struct oxygen *chip)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	cs2000_registers_init(chip);
59662306a36Sopenharmony_ci	xonar_stx_resume(chip);
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic void update_pcm1796_oversampling(struct oxygen *chip)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
60262306a36Sopenharmony_ci	unsigned int i;
60362306a36Sopenharmony_ci	u8 reg;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (data->current_rate <= 48000 && !data->h6)
60662306a36Sopenharmony_ci		reg = PCM1796_OS_128;
60762306a36Sopenharmony_ci	else
60862306a36Sopenharmony_ci		reg = PCM1796_OS_64;
60962306a36Sopenharmony_ci	for (i = 0; i < data->dacs; ++i)
61062306a36Sopenharmony_ci		pcm1796_write_cached(chip, i, 20, reg);
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistatic void update_pcm1796_deemph(struct oxygen *chip)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
61662306a36Sopenharmony_ci	unsigned int i;
61762306a36Sopenharmony_ci	u8 reg;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	reg = data->pcm1796_regs[0][18 - PCM1796_REG_BASE] & ~PCM1796_DMF_MASK;
62062306a36Sopenharmony_ci	if (data->current_rate == 48000)
62162306a36Sopenharmony_ci		reg |= PCM1796_DMF_48;
62262306a36Sopenharmony_ci	else if (data->current_rate == 44100)
62362306a36Sopenharmony_ci		reg |= PCM1796_DMF_441;
62462306a36Sopenharmony_ci	else if (data->current_rate == 32000)
62562306a36Sopenharmony_ci		reg |= PCM1796_DMF_32;
62662306a36Sopenharmony_ci	for (i = 0; i < data->dacs; ++i)
62762306a36Sopenharmony_ci		pcm1796_write_cached(chip, i, 18, reg);
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic void set_pcm1796_params(struct oxygen *chip,
63162306a36Sopenharmony_ci			       struct snd_pcm_hw_params *params)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	msleep(1);
63662306a36Sopenharmony_ci	data->current_rate = params_rate(params);
63762306a36Sopenharmony_ci	update_pcm1796_oversampling(chip);
63862306a36Sopenharmony_ci	update_pcm1796_deemph(chip);
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic void update_pcm1796_volume(struct oxygen *chip)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
64462306a36Sopenharmony_ci	unsigned int i;
64562306a36Sopenharmony_ci	s8 gain_offset;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	gain_offset = data->hp_active ? data->hp_gain_offset : 0;
64862306a36Sopenharmony_ci	for (i = 0; i < data->dacs; ++i) {
64962306a36Sopenharmony_ci		pcm1796_write_cached(chip, i, 16, chip->dac_volume[i * 2]
65062306a36Sopenharmony_ci				     + gain_offset);
65162306a36Sopenharmony_ci		pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1]
65262306a36Sopenharmony_ci				     + gain_offset);
65362306a36Sopenharmony_ci		gain_offset = 0;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic void update_pcm1796_mute(struct oxygen *chip)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
66062306a36Sopenharmony_ci	unsigned int i;
66162306a36Sopenharmony_ci	u8 value;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	value = data->pcm1796_regs[0][18 - PCM1796_REG_BASE];
66462306a36Sopenharmony_ci	if (chip->dac_mute)
66562306a36Sopenharmony_ci		value |= PCM1796_MUTE;
66662306a36Sopenharmony_ci	else
66762306a36Sopenharmony_ci		value &= ~PCM1796_MUTE;
66862306a36Sopenharmony_ci	for (i = 0; i < data->dacs; ++i)
66962306a36Sopenharmony_ci		pcm1796_write_cached(chip, i, 18, value);
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic void update_cs2000_rate(struct oxygen *chip, unsigned int rate)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
67562306a36Sopenharmony_ci	u8 rate_mclk, reg;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	switch (rate) {
67862306a36Sopenharmony_ci	case 32000:
67962306a36Sopenharmony_ci	case 64000:
68062306a36Sopenharmony_ci		rate_mclk = OXYGEN_RATE_32000;
68162306a36Sopenharmony_ci		break;
68262306a36Sopenharmony_ci	case 44100:
68362306a36Sopenharmony_ci	case 88200:
68462306a36Sopenharmony_ci	case 176400:
68562306a36Sopenharmony_ci		rate_mclk = OXYGEN_RATE_44100;
68662306a36Sopenharmony_ci		break;
68762306a36Sopenharmony_ci	default:
68862306a36Sopenharmony_ci	case 48000:
68962306a36Sopenharmony_ci	case 96000:
69062306a36Sopenharmony_ci	case 192000:
69162306a36Sopenharmony_ci		rate_mclk = OXYGEN_RATE_48000;
69262306a36Sopenharmony_ci		break;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (rate <= 96000 && (rate > 48000 || data->h6)) {
69662306a36Sopenharmony_ci		rate_mclk |= OXYGEN_I2S_MCLK(MCLK_256);
69762306a36Sopenharmony_ci		reg = CS2000_REF_CLK_DIV_1;
69862306a36Sopenharmony_ci	} else {
69962306a36Sopenharmony_ci		rate_mclk |= OXYGEN_I2S_MCLK(MCLK_512);
70062306a36Sopenharmony_ci		reg = CS2000_REF_CLK_DIV_2;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
70462306a36Sopenharmony_ci			      OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
70562306a36Sopenharmony_ci	cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg);
70662306a36Sopenharmony_ci	msleep(3); /* PLL lock delay */
70762306a36Sopenharmony_ci}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_cistatic void set_st_params(struct oxygen *chip,
71062306a36Sopenharmony_ci			  struct snd_pcm_hw_params *params)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	update_cs2000_rate(chip, params_rate(params));
71362306a36Sopenharmony_ci	set_pcm1796_params(chip, params);
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic void set_hdav_params(struct oxygen *chip,
71762306a36Sopenharmony_ci			    struct snd_pcm_hw_params *params)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	struct xonar_hdav *data = chip->model_data;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	set_pcm1796_params(chip, params);
72262306a36Sopenharmony_ci	xonar_set_hdmi_params(chip, &data->hdmi, params);
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic const struct snd_kcontrol_new alt_switch = {
72662306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
72762306a36Sopenharmony_ci	.name = "Analog Loopback Switch",
72862306a36Sopenharmony_ci	.info = snd_ctl_boolean_mono_info,
72962306a36Sopenharmony_ci	.get = xonar_gpio_bit_switch_get,
73062306a36Sopenharmony_ci	.put = xonar_gpio_bit_switch_put,
73162306a36Sopenharmony_ci	.private_value = GPIO_D2_ALT,
73262306a36Sopenharmony_ci};
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic int rolloff_info(struct snd_kcontrol *ctl,
73562306a36Sopenharmony_ci			struct snd_ctl_elem_info *info)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	static const char *const names[2] = {
73862306a36Sopenharmony_ci		"Sharp Roll-off", "Slow Roll-off"
73962306a36Sopenharmony_ci	};
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	return snd_ctl_enum_info(info, 1, 2, names);
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_cistatic int rolloff_get(struct snd_kcontrol *ctl,
74562306a36Sopenharmony_ci		       struct snd_ctl_elem_value *value)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
74862306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	value->value.enumerated.item[0] =
75162306a36Sopenharmony_ci		(data->pcm1796_regs[0][19 - PCM1796_REG_BASE] &
75262306a36Sopenharmony_ci		 PCM1796_FLT_MASK) != PCM1796_FLT_SHARP;
75362306a36Sopenharmony_ci	return 0;
75462306a36Sopenharmony_ci}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistatic int rolloff_put(struct snd_kcontrol *ctl,
75762306a36Sopenharmony_ci		       struct snd_ctl_elem_value *value)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
76062306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
76162306a36Sopenharmony_ci	unsigned int i;
76262306a36Sopenharmony_ci	int changed;
76362306a36Sopenharmony_ci	u8 reg;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	mutex_lock(&chip->mutex);
76662306a36Sopenharmony_ci	reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE];
76762306a36Sopenharmony_ci	reg &= ~PCM1796_FLT_MASK;
76862306a36Sopenharmony_ci	if (!value->value.enumerated.item[0])
76962306a36Sopenharmony_ci		reg |= PCM1796_FLT_SHARP;
77062306a36Sopenharmony_ci	else
77162306a36Sopenharmony_ci		reg |= PCM1796_FLT_SLOW;
77262306a36Sopenharmony_ci	changed = reg != data->pcm1796_regs[0][19 - PCM1796_REG_BASE];
77362306a36Sopenharmony_ci	if (changed) {
77462306a36Sopenharmony_ci		for (i = 0; i < data->dacs; ++i)
77562306a36Sopenharmony_ci			pcm1796_write(chip, i, 19, reg);
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci	mutex_unlock(&chip->mutex);
77862306a36Sopenharmony_ci	return changed;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic const struct snd_kcontrol_new rolloff_control = {
78262306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
78362306a36Sopenharmony_ci	.name = "DAC Filter Playback Enum",
78462306a36Sopenharmony_ci	.info = rolloff_info,
78562306a36Sopenharmony_ci	.get = rolloff_get,
78662306a36Sopenharmony_ci	.put = rolloff_put,
78762306a36Sopenharmony_ci};
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic int deemph_get(struct snd_kcontrol *ctl,
79062306a36Sopenharmony_ci		       struct snd_ctl_elem_value *value)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
79362306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	value->value.integer.value[0] =
79662306a36Sopenharmony_ci		!!(data->pcm1796_regs[0][18 - PCM1796_REG_BASE] & PCM1796_DME);
79762306a36Sopenharmony_ci	return 0;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic int deemph_put(struct snd_kcontrol *ctl,
80162306a36Sopenharmony_ci		       struct snd_ctl_elem_value *value)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
80462306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
80562306a36Sopenharmony_ci	unsigned int i;
80662306a36Sopenharmony_ci	int changed;
80762306a36Sopenharmony_ci	u8 reg;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	mutex_lock(&chip->mutex);
81062306a36Sopenharmony_ci	reg = data->pcm1796_regs[0][18 - PCM1796_REG_BASE];
81162306a36Sopenharmony_ci	if (!value->value.integer.value[0])
81262306a36Sopenharmony_ci		reg &= ~PCM1796_DME;
81362306a36Sopenharmony_ci	else
81462306a36Sopenharmony_ci		reg |= PCM1796_DME;
81562306a36Sopenharmony_ci	changed = reg != data->pcm1796_regs[0][18 - PCM1796_REG_BASE];
81662306a36Sopenharmony_ci	if (changed) {
81762306a36Sopenharmony_ci		for (i = 0; i < data->dacs; ++i)
81862306a36Sopenharmony_ci			pcm1796_write(chip, i, 18, reg);
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci	mutex_unlock(&chip->mutex);
82162306a36Sopenharmony_ci	return changed;
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_cistatic const struct snd_kcontrol_new deemph_control = {
82562306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
82662306a36Sopenharmony_ci	.name = "De-emphasis Playback Switch",
82762306a36Sopenharmony_ci	.info = snd_ctl_boolean_mono_info,
82862306a36Sopenharmony_ci	.get = deemph_get,
82962306a36Sopenharmony_ci	.put = deemph_put,
83062306a36Sopenharmony_ci};
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic const struct snd_kcontrol_new hdav_hdmi_control = {
83362306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
83462306a36Sopenharmony_ci	.name = "HDMI Playback Switch",
83562306a36Sopenharmony_ci	.info = snd_ctl_boolean_mono_info,
83662306a36Sopenharmony_ci	.get = xonar_gpio_bit_switch_get,
83762306a36Sopenharmony_ci	.put = xonar_gpio_bit_switch_put,
83862306a36Sopenharmony_ci	.private_value = GPIO_HDAV_OUTPUT_ENABLE | XONAR_GPIO_BIT_INVERT,
83962306a36Sopenharmony_ci};
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic int st_output_switch_info(struct snd_kcontrol *ctl,
84262306a36Sopenharmony_ci				 struct snd_ctl_elem_info *info)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	static const char *const names[3] = {
84562306a36Sopenharmony_ci		"Speakers", "Headphones", "FP Headphones"
84662306a36Sopenharmony_ci	};
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	return snd_ctl_enum_info(info, 1, 3, names);
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic int st_output_switch_get(struct snd_kcontrol *ctl,
85262306a36Sopenharmony_ci				struct snd_ctl_elem_value *value)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
85562306a36Sopenharmony_ci	u16 gpio;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
85862306a36Sopenharmony_ci	if (!(gpio & GPIO_ST_HP))
85962306a36Sopenharmony_ci		value->value.enumerated.item[0] = 0;
86062306a36Sopenharmony_ci	else if (gpio & GPIO_ST_HP_REAR)
86162306a36Sopenharmony_ci		value->value.enumerated.item[0] = 1;
86262306a36Sopenharmony_ci	else
86362306a36Sopenharmony_ci		value->value.enumerated.item[0] = 2;
86462306a36Sopenharmony_ci	return 0;
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cistatic int st_output_switch_put(struct snd_kcontrol *ctl,
86962306a36Sopenharmony_ci				struct snd_ctl_elem_value *value)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
87262306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
87362306a36Sopenharmony_ci	u16 gpio_old, gpio;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	mutex_lock(&chip->mutex);
87662306a36Sopenharmony_ci	gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
87762306a36Sopenharmony_ci	gpio = gpio_old;
87862306a36Sopenharmony_ci	switch (value->value.enumerated.item[0]) {
87962306a36Sopenharmony_ci	case 0:
88062306a36Sopenharmony_ci		gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR);
88162306a36Sopenharmony_ci		break;
88262306a36Sopenharmony_ci	case 1:
88362306a36Sopenharmony_ci		gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR;
88462306a36Sopenharmony_ci		break;
88562306a36Sopenharmony_ci	case 2:
88662306a36Sopenharmony_ci		gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR;
88762306a36Sopenharmony_ci		break;
88862306a36Sopenharmony_ci	}
88962306a36Sopenharmony_ci	oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
89062306a36Sopenharmony_ci	data->hp_active = gpio & GPIO_ST_HP;
89162306a36Sopenharmony_ci	update_pcm1796_volume(chip);
89262306a36Sopenharmony_ci	mutex_unlock(&chip->mutex);
89362306a36Sopenharmony_ci	return gpio != gpio_old;
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic int st_hp_volume_offset_info(struct snd_kcontrol *ctl,
89762306a36Sopenharmony_ci				    struct snd_ctl_elem_info *info)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	static const char *const names[4] = {
90062306a36Sopenharmony_ci		"< 32 ohms", "32-64 ohms", "64-300 ohms", "300-600 ohms"
90162306a36Sopenharmony_ci	};
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	return snd_ctl_enum_info(info, 1, 4, names);
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
90762306a36Sopenharmony_ci				   struct snd_ctl_elem_value *value)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
91062306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	mutex_lock(&chip->mutex);
91362306a36Sopenharmony_ci	if (data->hp_gain_offset < 2*-12)
91462306a36Sopenharmony_ci		value->value.enumerated.item[0] = 0;
91562306a36Sopenharmony_ci	else if (data->hp_gain_offset < 2*-6)
91662306a36Sopenharmony_ci		value->value.enumerated.item[0] = 1;
91762306a36Sopenharmony_ci	else if (data->hp_gain_offset < 0)
91862306a36Sopenharmony_ci		value->value.enumerated.item[0] = 2;
91962306a36Sopenharmony_ci	else
92062306a36Sopenharmony_ci		value->value.enumerated.item[0] = 3;
92162306a36Sopenharmony_ci	mutex_unlock(&chip->mutex);
92262306a36Sopenharmony_ci	return 0;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic int st_hp_volume_offset_put(struct snd_kcontrol *ctl,
92762306a36Sopenharmony_ci				   struct snd_ctl_elem_value *value)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	static const s8 offsets[] = { 2*-18, 2*-12, 2*-6, 0 };
93062306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
93162306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
93262306a36Sopenharmony_ci	s8 offset;
93362306a36Sopenharmony_ci	int changed;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	if (value->value.enumerated.item[0] > 3)
93662306a36Sopenharmony_ci		return -EINVAL;
93762306a36Sopenharmony_ci	offset = offsets[value->value.enumerated.item[0]];
93862306a36Sopenharmony_ci	mutex_lock(&chip->mutex);
93962306a36Sopenharmony_ci	changed = offset != data->hp_gain_offset;
94062306a36Sopenharmony_ci	if (changed) {
94162306a36Sopenharmony_ci		data->hp_gain_offset = offset;
94262306a36Sopenharmony_ci		update_pcm1796_volume(chip);
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci	mutex_unlock(&chip->mutex);
94562306a36Sopenharmony_ci	return changed;
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_cistatic const struct snd_kcontrol_new st_controls[] = {
94962306a36Sopenharmony_ci	{
95062306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
95162306a36Sopenharmony_ci		.name = "Analog Output",
95262306a36Sopenharmony_ci		.info = st_output_switch_info,
95362306a36Sopenharmony_ci		.get = st_output_switch_get,
95462306a36Sopenharmony_ci		.put = st_output_switch_put,
95562306a36Sopenharmony_ci	},
95662306a36Sopenharmony_ci	{
95762306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
95862306a36Sopenharmony_ci		.name = "Headphones Impedance Playback Enum",
95962306a36Sopenharmony_ci		.info = st_hp_volume_offset_info,
96062306a36Sopenharmony_ci		.get = st_hp_volume_offset_get,
96162306a36Sopenharmony_ci		.put = st_hp_volume_offset_put,
96262306a36Sopenharmony_ci	},
96362306a36Sopenharmony_ci};
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cistatic int xense_output_switch_get(struct snd_kcontrol *ctl,
96662306a36Sopenharmony_ci				   struct snd_ctl_elem_value *value)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
96962306a36Sopenharmony_ci	u16 gpio;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
97262306a36Sopenharmony_ci	if (gpio & GPIO_XENSE_SPEAKERS)
97362306a36Sopenharmony_ci		value->value.enumerated.item[0] = 0;
97462306a36Sopenharmony_ci	else if (!(gpio & GPIO_XENSE_SPEAKERS) && (gpio & GPIO_ST_HP_REAR))
97562306a36Sopenharmony_ci		value->value.enumerated.item[0] = 1;
97662306a36Sopenharmony_ci	else
97762306a36Sopenharmony_ci		value->value.enumerated.item[0] = 2;
97862306a36Sopenharmony_ci	return 0;
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic int xense_output_switch_put(struct snd_kcontrol *ctl,
98262306a36Sopenharmony_ci				   struct snd_ctl_elem_value *value)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	struct oxygen *chip = ctl->private_data;
98562306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
98662306a36Sopenharmony_ci	u16 gpio_old, gpio;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	mutex_lock(&chip->mutex);
98962306a36Sopenharmony_ci	gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
99062306a36Sopenharmony_ci	gpio = gpio_old;
99162306a36Sopenharmony_ci	switch (value->value.enumerated.item[0]) {
99262306a36Sopenharmony_ci	case 0:
99362306a36Sopenharmony_ci		gpio |= GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR;
99462306a36Sopenharmony_ci		break;
99562306a36Sopenharmony_ci	case 1:
99662306a36Sopenharmony_ci		gpio = (gpio | GPIO_ST_HP_REAR) & ~GPIO_XENSE_SPEAKERS;
99762306a36Sopenharmony_ci		break;
99862306a36Sopenharmony_ci	case 2:
99962306a36Sopenharmony_ci		gpio &= ~(GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR);
100062306a36Sopenharmony_ci		break;
100162306a36Sopenharmony_ci	}
100262306a36Sopenharmony_ci	oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
100362306a36Sopenharmony_ci	data->hp_active = !(gpio & GPIO_XENSE_SPEAKERS);
100462306a36Sopenharmony_ci	update_pcm1796_volume(chip);
100562306a36Sopenharmony_ci	mutex_unlock(&chip->mutex);
100662306a36Sopenharmony_ci	return gpio != gpio_old;
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic const struct snd_kcontrol_new xense_controls[] = {
101062306a36Sopenharmony_ci	{
101162306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
101262306a36Sopenharmony_ci		.name = "Analog Output",
101362306a36Sopenharmony_ci		.info = st_output_switch_info,
101462306a36Sopenharmony_ci		.get = xense_output_switch_get,
101562306a36Sopenharmony_ci		.put = xense_output_switch_put,
101662306a36Sopenharmony_ci	},
101762306a36Sopenharmony_ci	{
101862306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
101962306a36Sopenharmony_ci		.name = "Headphones Impedance Playback Enum",
102062306a36Sopenharmony_ci		.info = st_hp_volume_offset_info,
102162306a36Sopenharmony_ci		.get = st_hp_volume_offset_get,
102262306a36Sopenharmony_ci		.put = st_hp_volume_offset_put,
102362306a36Sopenharmony_ci	},
102462306a36Sopenharmony_ci};
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cistatic void xonar_line_mic_ac97_switch(struct oxygen *chip,
102762306a36Sopenharmony_ci				       unsigned int reg, unsigned int mute)
102862306a36Sopenharmony_ci{
102962306a36Sopenharmony_ci	if (reg == AC97_LINE) {
103062306a36Sopenharmony_ci		spin_lock_irq(&chip->reg_lock);
103162306a36Sopenharmony_ci		oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
103262306a36Sopenharmony_ci				      mute ? GPIO_INPUT_ROUTE : 0,
103362306a36Sopenharmony_ci				      GPIO_INPUT_ROUTE);
103462306a36Sopenharmony_ci		spin_unlock_irq(&chip->reg_lock);
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cistatic int xonar_d2_control_filter(struct snd_kcontrol_new *template)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	if (!strncmp(template->name, "CD Capture ", 11))
104362306a36Sopenharmony_ci		/* CD in is actually connected to the video in pin */
104462306a36Sopenharmony_ci		template->private_value ^= AC97_CD ^ AC97_VIDEO;
104562306a36Sopenharmony_ci	return 0;
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic int xonar_st_h6_control_filter(struct snd_kcontrol_new *template)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	if (!strncmp(template->name, "Master Playback ", 16))
105162306a36Sopenharmony_ci		/* no volume/mute, as I²C to the third DAC does not work */
105262306a36Sopenharmony_ci		return 1;
105362306a36Sopenharmony_ci	return 0;
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_cistatic int add_pcm1796_controls(struct oxygen *chip)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
105962306a36Sopenharmony_ci	int err;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	if (!data->broken_i2c) {
106262306a36Sopenharmony_ci		err = snd_ctl_add(chip->card,
106362306a36Sopenharmony_ci				  snd_ctl_new1(&rolloff_control, chip));
106462306a36Sopenharmony_ci		if (err < 0)
106562306a36Sopenharmony_ci			return err;
106662306a36Sopenharmony_ci		err = snd_ctl_add(chip->card,
106762306a36Sopenharmony_ci				  snd_ctl_new1(&deemph_control, chip));
106862306a36Sopenharmony_ci		if (err < 0)
106962306a36Sopenharmony_ci			return err;
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci	return 0;
107262306a36Sopenharmony_ci}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_cistatic int xonar_d2_mixer_init(struct oxygen *chip)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	int err;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
107962306a36Sopenharmony_ci	if (err < 0)
108062306a36Sopenharmony_ci		return err;
108162306a36Sopenharmony_ci	err = add_pcm1796_controls(chip);
108262306a36Sopenharmony_ci	if (err < 0)
108362306a36Sopenharmony_ci		return err;
108462306a36Sopenharmony_ci	return 0;
108562306a36Sopenharmony_ci}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_cistatic int xonar_hdav_mixer_init(struct oxygen *chip)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	int err;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	err = snd_ctl_add(chip->card, snd_ctl_new1(&hdav_hdmi_control, chip));
109262306a36Sopenharmony_ci	if (err < 0)
109362306a36Sopenharmony_ci		return err;
109462306a36Sopenharmony_ci	err = add_pcm1796_controls(chip);
109562306a36Sopenharmony_ci	if (err < 0)
109662306a36Sopenharmony_ci		return err;
109762306a36Sopenharmony_ci	return 0;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_cistatic int xonar_st_mixer_init(struct oxygen *chip)
110162306a36Sopenharmony_ci{
110262306a36Sopenharmony_ci	unsigned int i;
110362306a36Sopenharmony_ci	int err;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(st_controls); ++i) {
110662306a36Sopenharmony_ci		err = snd_ctl_add(chip->card,
110762306a36Sopenharmony_ci				  snd_ctl_new1(&st_controls[i], chip));
110862306a36Sopenharmony_ci		if (err < 0)
110962306a36Sopenharmony_ci			return err;
111062306a36Sopenharmony_ci	}
111162306a36Sopenharmony_ci	err = add_pcm1796_controls(chip);
111262306a36Sopenharmony_ci	if (err < 0)
111362306a36Sopenharmony_ci		return err;
111462306a36Sopenharmony_ci	return 0;
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_cistatic int xonar_xense_mixer_init(struct oxygen *chip)
111862306a36Sopenharmony_ci{
111962306a36Sopenharmony_ci	unsigned int i;
112062306a36Sopenharmony_ci	int err;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(xense_controls); ++i) {
112362306a36Sopenharmony_ci		err = snd_ctl_add(chip->card,
112462306a36Sopenharmony_ci		snd_ctl_new1(&xense_controls[i], chip));
112562306a36Sopenharmony_ci		if (err < 0)
112662306a36Sopenharmony_ci			return err;
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci	err = add_pcm1796_controls(chip);
112962306a36Sopenharmony_ci	if (err < 0)
113062306a36Sopenharmony_ci		return err;
113162306a36Sopenharmony_ci	return 0;
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic void dump_pcm1796_registers(struct oxygen *chip,
113562306a36Sopenharmony_ci				   struct snd_info_buffer *buffer)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
113862306a36Sopenharmony_ci	unsigned int dac, i;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	for (dac = 0; dac < data->dacs; ++dac) {
114162306a36Sopenharmony_ci		snd_iprintf(buffer, "\nPCM1796 %u:", dac + 1);
114262306a36Sopenharmony_ci		for (i = 0; i < 5; ++i)
114362306a36Sopenharmony_ci			snd_iprintf(buffer, " %02x",
114462306a36Sopenharmony_ci				    data->pcm1796_regs[dac][i]);
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci	snd_iprintf(buffer, "\n");
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_cistatic void dump_cs2000_registers(struct oxygen *chip,
115062306a36Sopenharmony_ci				  struct snd_info_buffer *buffer)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	struct xonar_pcm179x *data = chip->model_data;
115362306a36Sopenharmony_ci	unsigned int i;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	if (data->has_cs2000) {
115662306a36Sopenharmony_ci		snd_iprintf(buffer, "\nCS2000:\n00:   ");
115762306a36Sopenharmony_ci		for (i = 1; i < 0x10; ++i)
115862306a36Sopenharmony_ci			snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);
115962306a36Sopenharmony_ci		snd_iprintf(buffer, "\n10:");
116062306a36Sopenharmony_ci		for (i = 0x10; i < 0x1f; ++i)
116162306a36Sopenharmony_ci			snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);
116262306a36Sopenharmony_ci		snd_iprintf(buffer, "\n");
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic void dump_st_registers(struct oxygen *chip,
116762306a36Sopenharmony_ci			      struct snd_info_buffer *buffer)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	dump_pcm1796_registers(chip, buffer);
117062306a36Sopenharmony_ci	dump_cs2000_registers(chip, buffer);
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic const struct oxygen_model model_xonar_d2 = {
117462306a36Sopenharmony_ci	.longname = "Asus Virtuoso 200",
117562306a36Sopenharmony_ci	.chip = "AV200",
117662306a36Sopenharmony_ci	.init = xonar_d2_init,
117762306a36Sopenharmony_ci	.control_filter = xonar_d2_control_filter,
117862306a36Sopenharmony_ci	.mixer_init = xonar_d2_mixer_init,
117962306a36Sopenharmony_ci	.cleanup = xonar_d2_cleanup,
118062306a36Sopenharmony_ci	.suspend = xonar_d2_suspend,
118162306a36Sopenharmony_ci	.resume = xonar_d2_resume,
118262306a36Sopenharmony_ci	.set_dac_params = set_pcm1796_params,
118362306a36Sopenharmony_ci	.set_adc_params = xonar_set_cs53x1_params,
118462306a36Sopenharmony_ci	.update_dac_volume = update_pcm1796_volume,
118562306a36Sopenharmony_ci	.update_dac_mute = update_pcm1796_mute,
118662306a36Sopenharmony_ci	.dump_registers = dump_pcm1796_registers,
118762306a36Sopenharmony_ci	.dac_tlv = pcm1796_db_scale,
118862306a36Sopenharmony_ci	.model_data_size = sizeof(struct xonar_pcm179x),
118962306a36Sopenharmony_ci	.device_config = PLAYBACK_0_TO_I2S |
119062306a36Sopenharmony_ci			 PLAYBACK_1_TO_SPDIF |
119162306a36Sopenharmony_ci			 CAPTURE_0_FROM_I2S_2 |
119262306a36Sopenharmony_ci			 CAPTURE_1_FROM_SPDIF |
119362306a36Sopenharmony_ci			 MIDI_OUTPUT |
119462306a36Sopenharmony_ci			 MIDI_INPUT |
119562306a36Sopenharmony_ci			 AC97_CD_INPUT,
119662306a36Sopenharmony_ci	.dac_channels_pcm = 8,
119762306a36Sopenharmony_ci	.dac_channels_mixer = 8,
119862306a36Sopenharmony_ci	.dac_volume_min = 255 - 2*60,
119962306a36Sopenharmony_ci	.dac_volume_max = 255,
120062306a36Sopenharmony_ci	.misc_flags = OXYGEN_MISC_MIDI,
120162306a36Sopenharmony_ci	.function_flags = OXYGEN_FUNCTION_SPI |
120262306a36Sopenharmony_ci			  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
120362306a36Sopenharmony_ci	.dac_mclks = OXYGEN_MCLKS(512, 128, 128),
120462306a36Sopenharmony_ci	.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
120562306a36Sopenharmony_ci	.dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
120662306a36Sopenharmony_ci	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
120762306a36Sopenharmony_ci};
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_cistatic const struct oxygen_model model_xonar_hdav = {
121062306a36Sopenharmony_ci	.longname = "Asus Virtuoso 200",
121162306a36Sopenharmony_ci	.chip = "AV200",
121262306a36Sopenharmony_ci	.init = xonar_hdav_init,
121362306a36Sopenharmony_ci	.mixer_init = xonar_hdav_mixer_init,
121462306a36Sopenharmony_ci	.cleanup = xonar_hdav_cleanup,
121562306a36Sopenharmony_ci	.suspend = xonar_hdav_suspend,
121662306a36Sopenharmony_ci	.resume = xonar_hdav_resume,
121762306a36Sopenharmony_ci	.pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter,
121862306a36Sopenharmony_ci	.set_dac_params = set_hdav_params,
121962306a36Sopenharmony_ci	.set_adc_params = xonar_set_cs53x1_params,
122062306a36Sopenharmony_ci	.update_dac_volume = update_pcm1796_volume,
122162306a36Sopenharmony_ci	.update_dac_mute = update_pcm1796_mute,
122262306a36Sopenharmony_ci	.uart_input = xonar_hdmi_uart_input,
122362306a36Sopenharmony_ci	.ac97_switch = xonar_line_mic_ac97_switch,
122462306a36Sopenharmony_ci	.dump_registers = dump_pcm1796_registers,
122562306a36Sopenharmony_ci	.dac_tlv = pcm1796_db_scale,
122662306a36Sopenharmony_ci	.model_data_size = sizeof(struct xonar_hdav),
122762306a36Sopenharmony_ci	.device_config = PLAYBACK_0_TO_I2S |
122862306a36Sopenharmony_ci			 PLAYBACK_1_TO_SPDIF |
122962306a36Sopenharmony_ci			 CAPTURE_0_FROM_I2S_2 |
123062306a36Sopenharmony_ci			 CAPTURE_1_FROM_SPDIF,
123162306a36Sopenharmony_ci	.dac_channels_pcm = 8,
123262306a36Sopenharmony_ci	.dac_channels_mixer = 2,
123362306a36Sopenharmony_ci	.dac_volume_min = 255 - 2*60,
123462306a36Sopenharmony_ci	.dac_volume_max = 255,
123562306a36Sopenharmony_ci	.misc_flags = OXYGEN_MISC_MIDI,
123662306a36Sopenharmony_ci	.function_flags = OXYGEN_FUNCTION_2WIRE,
123762306a36Sopenharmony_ci	.dac_mclks = OXYGEN_MCLKS(512, 128, 128),
123862306a36Sopenharmony_ci	.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
123962306a36Sopenharmony_ci	.dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
124062306a36Sopenharmony_ci	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
124162306a36Sopenharmony_ci};
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_cistatic const struct oxygen_model model_xonar_st = {
124462306a36Sopenharmony_ci	.longname = "Asus Virtuoso 100",
124562306a36Sopenharmony_ci	.chip = "AV200",
124662306a36Sopenharmony_ci	.init = xonar_st_init,
124762306a36Sopenharmony_ci	.mixer_init = xonar_st_mixer_init,
124862306a36Sopenharmony_ci	.cleanup = xonar_st_cleanup,
124962306a36Sopenharmony_ci	.suspend = xonar_st_suspend,
125062306a36Sopenharmony_ci	.resume = xonar_st_resume,
125162306a36Sopenharmony_ci	.set_dac_params = set_st_params,
125262306a36Sopenharmony_ci	.set_adc_params = xonar_set_cs53x1_params,
125362306a36Sopenharmony_ci	.update_dac_volume = update_pcm1796_volume,
125462306a36Sopenharmony_ci	.update_dac_mute = update_pcm1796_mute,
125562306a36Sopenharmony_ci	.ac97_switch = xonar_line_mic_ac97_switch,
125662306a36Sopenharmony_ci	.dump_registers = dump_st_registers,
125762306a36Sopenharmony_ci	.dac_tlv = pcm1796_db_scale,
125862306a36Sopenharmony_ci	.model_data_size = sizeof(struct xonar_pcm179x),
125962306a36Sopenharmony_ci	.device_config = PLAYBACK_0_TO_I2S |
126062306a36Sopenharmony_ci			 PLAYBACK_1_TO_SPDIF |
126162306a36Sopenharmony_ci			 CAPTURE_0_FROM_I2S_2 |
126262306a36Sopenharmony_ci			 CAPTURE_1_FROM_SPDIF |
126362306a36Sopenharmony_ci			 AC97_FMIC_SWITCH,
126462306a36Sopenharmony_ci	.dac_channels_pcm = 2,
126562306a36Sopenharmony_ci	.dac_channels_mixer = 2,
126662306a36Sopenharmony_ci	.dac_volume_min = 255 - 2*60,
126762306a36Sopenharmony_ci	.dac_volume_max = 255,
126862306a36Sopenharmony_ci	.function_flags = OXYGEN_FUNCTION_2WIRE,
126962306a36Sopenharmony_ci	.dac_mclks = OXYGEN_MCLKS(512, 128, 128),
127062306a36Sopenharmony_ci	.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
127162306a36Sopenharmony_ci	.dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
127262306a36Sopenharmony_ci	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
127362306a36Sopenharmony_ci};
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ciint get_xonar_pcm179x_model(struct oxygen *chip,
127662306a36Sopenharmony_ci			    const struct pci_device_id *id)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	switch (id->subdevice) {
127962306a36Sopenharmony_ci	case 0x8269:
128062306a36Sopenharmony_ci		chip->model = model_xonar_d2;
128162306a36Sopenharmony_ci		chip->model.shortname = "Xonar D2";
128262306a36Sopenharmony_ci		break;
128362306a36Sopenharmony_ci	case 0x82b7:
128462306a36Sopenharmony_ci		chip->model = model_xonar_d2;
128562306a36Sopenharmony_ci		chip->model.shortname = "Xonar D2X";
128662306a36Sopenharmony_ci		chip->model.init = xonar_d2x_init;
128762306a36Sopenharmony_ci		break;
128862306a36Sopenharmony_ci	case 0x8314:
128962306a36Sopenharmony_ci		chip->model = model_xonar_hdav;
129062306a36Sopenharmony_ci		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
129162306a36Sopenharmony_ci		switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
129262306a36Sopenharmony_ci		default:
129362306a36Sopenharmony_ci			chip->model.shortname = "Xonar HDAV1.3";
129462306a36Sopenharmony_ci			break;
129562306a36Sopenharmony_ci		case GPIO_DB_H6:
129662306a36Sopenharmony_ci			chip->model.shortname = "Xonar HDAV1.3+H6";
129762306a36Sopenharmony_ci			chip->model.dac_channels_mixer = 8;
129862306a36Sopenharmony_ci			chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
129962306a36Sopenharmony_ci			break;
130062306a36Sopenharmony_ci		}
130162306a36Sopenharmony_ci		break;
130262306a36Sopenharmony_ci	case 0x835d:
130362306a36Sopenharmony_ci		chip->model = model_xonar_st;
130462306a36Sopenharmony_ci		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
130562306a36Sopenharmony_ci		switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
130662306a36Sopenharmony_ci		default:
130762306a36Sopenharmony_ci			chip->model.shortname = "Xonar ST";
130862306a36Sopenharmony_ci			break;
130962306a36Sopenharmony_ci		case GPIO_DB_H6:
131062306a36Sopenharmony_ci			chip->model.shortname = "Xonar ST+H6";
131162306a36Sopenharmony_ci			chip->model.control_filter = xonar_st_h6_control_filter;
131262306a36Sopenharmony_ci			chip->model.dac_channels_pcm = 8;
131362306a36Sopenharmony_ci			chip->model.dac_channels_mixer = 8;
131462306a36Sopenharmony_ci			chip->model.dac_volume_min = 255;
131562306a36Sopenharmony_ci			chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
131662306a36Sopenharmony_ci			break;
131762306a36Sopenharmony_ci		}
131862306a36Sopenharmony_ci		break;
131962306a36Sopenharmony_ci	case 0x835c:
132062306a36Sopenharmony_ci		chip->model = model_xonar_st;
132162306a36Sopenharmony_ci		chip->model.shortname = "Xonar STX";
132262306a36Sopenharmony_ci		chip->model.init = xonar_stx_init;
132362306a36Sopenharmony_ci		chip->model.resume = xonar_stx_resume;
132462306a36Sopenharmony_ci		chip->model.set_dac_params = set_pcm1796_params;
132562306a36Sopenharmony_ci		break;
132662306a36Sopenharmony_ci	case 0x85f4:
132762306a36Sopenharmony_ci		chip->model = model_xonar_st;
132862306a36Sopenharmony_ci		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
132962306a36Sopenharmony_ci		switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
133062306a36Sopenharmony_ci		default:
133162306a36Sopenharmony_ci			chip->model.shortname = "Xonar STX II";
133262306a36Sopenharmony_ci			break;
133362306a36Sopenharmony_ci		case GPIO_DB_H6:
133462306a36Sopenharmony_ci			chip->model.shortname = "Xonar STX II+H6";
133562306a36Sopenharmony_ci			chip->model.dac_channels_pcm = 8;
133662306a36Sopenharmony_ci			chip->model.dac_channels_mixer = 8;
133762306a36Sopenharmony_ci			chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
133862306a36Sopenharmony_ci			break;
133962306a36Sopenharmony_ci		}
134062306a36Sopenharmony_ci		chip->model.init = xonar_stx_init;
134162306a36Sopenharmony_ci		chip->model.resume = xonar_stx_resume;
134262306a36Sopenharmony_ci		chip->model.set_dac_params = set_pcm1796_params;
134362306a36Sopenharmony_ci		break;
134462306a36Sopenharmony_ci	case 0x8428:
134562306a36Sopenharmony_ci		chip->model = model_xonar_st;
134662306a36Sopenharmony_ci		chip->model.shortname = "Xonar Xense";
134762306a36Sopenharmony_ci		chip->model.chip = "AV100";
134862306a36Sopenharmony_ci		chip->model.init = xonar_xense_init;
134962306a36Sopenharmony_ci		chip->model.mixer_init = xonar_xense_mixer_init;
135062306a36Sopenharmony_ci		break;
135162306a36Sopenharmony_ci	default:
135262306a36Sopenharmony_ci		return -EINVAL;
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci	return 0;
135562306a36Sopenharmony_ci}
1356