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