Path: blob/master/sound/pci/oxygen/xonar_pcm179x.c
10817 views
/*1* card driver for models with PCM1796 DACs (Xonar D2/D2X/HDAV1.3/ST/STX)2*3* Copyright (c) Clemens Ladisch <[email protected]>4*5*6* This driver is free software; you can redistribute it and/or modify7* it under the terms of the GNU General Public License, version 2.8*9* This driver is distributed in the hope that it will be useful,10* but WITHOUT ANY WARRANTY; without even the implied warranty of11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12* GNU General Public License for more details.13*14* You should have received a copy of the GNU General Public License15* along with this driver; if not, see <http://www.gnu.org/licenses/>.16*/1718/*19* Xonar D2/D2X20* ------------21*22* CMI8788:23*24* SPI 0 -> 1st PCM1796 (front)25* SPI 1 -> 2nd PCM1796 (surround)26* SPI 2 -> 3rd PCM1796 (center/LFE)27* SPI 4 -> 4th PCM1796 (back)28*29* GPIO 2 -> M0 of CS538130* GPIO 3 -> M1 of CS538131* GPIO 5 <- external power present (D2X only)32* GPIO 7 -> ALT33* GPIO 8 -> enable output to speakers34*35* CM9780:36*37* LINE_OUT -> input of ADC38*39* AUX_IN <- aux40* VIDEO_IN <- CD41* FMIC_IN <- mic42*43* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input44*/4546/*47* Xonar HDAV1.3 (Deluxe)48* ----------------------49*50* CMI8788:51*52* I²C <-> PCM1796 (addr 1001100) (front)53*54* GPI 0 <- external power present55*56* GPIO 0 -> enable HDMI (0) or speaker (1) output57* GPIO 2 -> M0 of CS538158* GPIO 3 -> M1 of CS538159* GPIO 4 <- daughterboard detection60* GPIO 5 <- daughterboard detection61* GPIO 6 -> ?62* GPIO 7 -> ?63* GPIO 8 -> route input jack to line-in (0) or mic-in (1)64*65* UART <-> HDMI controller66*67* CM9780:68*69* LINE_OUT -> input of ADC70*71* AUX_IN <- aux72* CD_IN <- CD73* MIC_IN <- mic74*75* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input76*77* no daughterboard78* ----------------79*80* GPIO 4 <- 181*82* H6 daughterboard83* ----------------84*85* GPIO 4 <- 086* GPIO 5 <- 087*88* I²C <-> PCM1796 (addr 1001101) (surround)89* <-> PCM1796 (addr 1001110) (center/LFE)90* <-> PCM1796 (addr 1001111) (back)91*92* unknown daughterboard93* ---------------------94*95* GPIO 4 <- 096* GPIO 5 <- 197*98* I²C <-> CS4362A (addr 0011000) (surround, center/LFE, back)99*/100101/*102* Xonar Essence ST (Deluxe)/STX103* -----------------------------104*105* CMI8788:106*107* I²C <-> PCM1792A (addr 1001100)108* <-> CS2000 (addr 1001110) (ST only)109*110* ADC1 MCLK -> REF_CLK of CS2000 (ST only)111*112* GPI 0 <- external power present (STX only)113*114* GPIO 0 -> enable output to speakers115* GPIO 1 -> route HP to front panel (0) or rear jack (1)116* GPIO 2 -> M0 of CS5381117* GPIO 3 -> M1 of CS5381118* GPIO 4 <- daughterboard detection119* GPIO 5 <- daughterboard detection120* GPIO 6 -> ?121* GPIO 7 -> route output to speaker jacks (0) or HP (1)122* GPIO 8 -> route input jack to line-in (0) or mic-in (1)123*124* PCM1792A:125*126* SCK <- CLK_OUT of CS2000 (ST only)127*128* CM9780:129*130* LINE_OUT -> input of ADC131*132* AUX_IN <- aux133* MIC_IN <- mic134*135* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input136*137* H6 daughterboard138* ----------------139*140* GPIO 4 <- 0141* GPIO 5 <- 0142*/143144/*145* Xonar Xense146* -----------147*148* CMI8788:149*150* I²C <-> PCM1796 (addr 1001100) (front)151* <-> CS4362A (addr 0011000) (surround, center/LFE, back)152* <-> CS2000 (addr 1001110)153*154* ADC1 MCLK -> REF_CLK of CS2000155*156* GPI 0 <- external power present157*158* GPIO 0 -> enable output159* GPIO 1 -> route HP to front panel (0) or rear jack (1)160* GPIO 2 -> M0 of CS5381161* GPIO 3 -> M1 of CS5381162* GPIO 4 -> enable output163* GPIO 5 -> enable output164* GPIO 6 -> ?165* GPIO 7 -> route output to HP (0) or speaker (1)166* GPIO 8 -> route input jack to mic-in (0) or line-in (1)167*168* CM9780:169*170* LINE_OUT -> input of ADC171*172* AUX_IN <- aux173* VIDEO_IN <- ?174* FMIC_IN <- mic175*176* GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input177* GPO 1 -> route mic-in from input jack (0) or front panel header (1)178*/179180#include <linux/pci.h>181#include <linux/delay.h>182#include <linux/mutex.h>183#include <sound/ac97_codec.h>184#include <sound/control.h>185#include <sound/core.h>186#include <sound/info.h>187#include <sound/pcm.h>188#include <sound/pcm_params.h>189#include <sound/tlv.h>190#include "xonar.h"191#include "cm9780.h"192#include "pcm1796.h"193#include "cs2000.h"194195196#define GPIO_D2X_EXT_POWER 0x0020197#define GPIO_D2_ALT 0x0080198#define GPIO_D2_OUTPUT_ENABLE 0x0100199200#define GPI_EXT_POWER 0x01201#define GPIO_INPUT_ROUTE 0x0100202203#define GPIO_HDAV_OUTPUT_ENABLE 0x0001204#define GPIO_HDAV_MAGIC 0x00c0205206#define GPIO_DB_MASK 0x0030207#define GPIO_DB_H6 0x0000208209#define GPIO_ST_OUTPUT_ENABLE 0x0001210#define GPIO_ST_HP_REAR 0x0002211#define GPIO_ST_MAGIC 0x0040212#define GPIO_ST_HP 0x0080213214#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */215#define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /W=0 */216217#define PCM1796_REG_BASE 16218219220struct xonar_pcm179x {221struct xonar_generic generic;222unsigned int dacs;223u8 pcm1796_regs[4][5];224unsigned int current_rate;225bool h6;226bool hp_active;227s8 hp_gain_offset;228bool has_cs2000;229u8 cs2000_regs[0x1f];230bool broken_i2c;231};232233struct xonar_hdav {234struct xonar_pcm179x pcm179x;235struct xonar_hdmi hdmi;236};237238239static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,240u8 reg, u8 value)241{242/* maps ALSA channel pair number to SPI output */243static const u8 codec_map[4] = {2440, 1, 2, 4245};246oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |247OXYGEN_SPI_DATA_LENGTH_2 |248OXYGEN_SPI_CLOCK_160 |249(codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |250OXYGEN_SPI_CEN_LATCH_CLOCK_HI,251(reg << 8) | value);252}253254static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,255u8 reg, u8 value)256{257oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value);258}259260static void pcm1796_write(struct oxygen *chip, unsigned int codec,261u8 reg, u8 value)262{263struct xonar_pcm179x *data = chip->model_data;264265if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==266OXYGEN_FUNCTION_SPI)267pcm1796_write_spi(chip, codec, reg, value);268else269pcm1796_write_i2c(chip, codec, reg, value);270if ((unsigned int)(reg - PCM1796_REG_BASE)271< ARRAY_SIZE(data->pcm1796_regs[codec]))272data->pcm1796_regs[codec][reg - PCM1796_REG_BASE] = value;273}274275static void pcm1796_write_cached(struct oxygen *chip, unsigned int codec,276u8 reg, u8 value)277{278struct xonar_pcm179x *data = chip->model_data;279280if (value != data->pcm1796_regs[codec][reg - PCM1796_REG_BASE])281pcm1796_write(chip, codec, reg, value);282}283284static void cs2000_write(struct oxygen *chip, u8 reg, u8 value)285{286struct xonar_pcm179x *data = chip->model_data;287288oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value);289data->cs2000_regs[reg] = value;290}291292static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value)293{294struct xonar_pcm179x *data = chip->model_data;295296if (value != data->cs2000_regs[reg])297cs2000_write(chip, reg, value);298}299300static void pcm1796_registers_init(struct oxygen *chip)301{302struct xonar_pcm179x *data = chip->model_data;303unsigned int i;304s8 gain_offset;305306msleep(1);307gain_offset = data->hp_active ? data->hp_gain_offset : 0;308for (i = 0; i < data->dacs; ++i) {309/* set ATLD before ATL/ATR */310pcm1796_write(chip, i, 18,311data->pcm1796_regs[0][18 - PCM1796_REG_BASE]);312pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]313+ gain_offset);314pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]315+ gain_offset);316pcm1796_write(chip, i, 19,317data->pcm1796_regs[0][19 - PCM1796_REG_BASE]);318pcm1796_write(chip, i, 20,319data->pcm1796_regs[0][20 - PCM1796_REG_BASE]);320pcm1796_write(chip, i, 21, 0);321gain_offset = 0;322}323}324325static void pcm1796_init(struct oxygen *chip)326{327struct xonar_pcm179x *data = chip->model_data;328329data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE |330PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;331data->pcm1796_regs[0][19 - PCM1796_REG_BASE] =332PCM1796_FLT_SHARP | PCM1796_ATS_1;333data->pcm1796_regs[0][20 - PCM1796_REG_BASE] =334data->h6 ? PCM1796_OS_64 : PCM1796_OS_128;335pcm1796_registers_init(chip);336data->current_rate = 48000;337}338339static void xonar_d2_init(struct oxygen *chip)340{341struct xonar_pcm179x *data = chip->model_data;342343data->generic.anti_pop_delay = 300;344data->generic.output_enable_bit = GPIO_D2_OUTPUT_ENABLE;345data->dacs = 4;346347pcm1796_init(chip);348349oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT);350oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT);351352oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);353354xonar_init_cs53x1(chip);355xonar_enable_output(chip);356357snd_component_add(chip->card, "PCM1796");358snd_component_add(chip->card, "CS5381");359}360361static void xonar_d2x_init(struct oxygen *chip)362{363struct xonar_pcm179x *data = chip->model_data;364365data->generic.ext_power_reg = OXYGEN_GPIO_DATA;366data->generic.ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;367data->generic.ext_power_bit = GPIO_D2X_EXT_POWER;368oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);369xonar_init_ext_power(chip);370xonar_d2_init(chip);371}372373static void xonar_hdav_init(struct oxygen *chip)374{375struct xonar_hdav *data = chip->model_data;376377oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,378OXYGEN_2WIRE_LENGTH_8 |379OXYGEN_2WIRE_INTERRUPT_MASK |380OXYGEN_2WIRE_SPEED_STANDARD);381382data->pcm179x.generic.anti_pop_delay = 100;383data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE;384data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA;385data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;386data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER;387data->pcm179x.dacs = chip->model.dac_channels_mixer / 2;388data->pcm179x.h6 = chip->model.dac_channels_mixer > 2;389390pcm1796_init(chip);391392oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,393GPIO_HDAV_MAGIC | GPIO_INPUT_ROUTE);394oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);395396xonar_init_cs53x1(chip);397xonar_init_ext_power(chip);398xonar_hdmi_init(chip, &data->hdmi);399xonar_enable_output(chip);400401snd_component_add(chip->card, "PCM1796");402snd_component_add(chip->card, "CS5381");403}404405static void xonar_st_init_i2c(struct oxygen *chip)406{407oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,408OXYGEN_2WIRE_LENGTH_8 |409OXYGEN_2WIRE_INTERRUPT_MASK |410OXYGEN_2WIRE_SPEED_STANDARD);411}412413static void xonar_st_init_common(struct oxygen *chip)414{415struct xonar_pcm179x *data = chip->model_data;416417data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;418data->dacs = chip->model.dac_channels_mixer / 2;419data->hp_gain_offset = 2*-18;420421pcm1796_init(chip);422423oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,424GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |425GPIO_ST_MAGIC | GPIO_ST_HP);426oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,427GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);428429xonar_init_cs53x1(chip);430xonar_enable_output(chip);431432snd_component_add(chip->card, "PCM1792A");433snd_component_add(chip->card, "CS5381");434}435436static void cs2000_registers_init(struct oxygen *chip)437{438struct xonar_pcm179x *data = chip->model_data;439440cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_FREEZE);441cs2000_write(chip, CS2000_DEV_CTRL, 0);442cs2000_write(chip, CS2000_DEV_CFG_1,443CS2000_R_MOD_SEL_1 |444(0 << CS2000_R_SEL_SHIFT) |445CS2000_AUX_OUT_SRC_REF_CLK |446CS2000_EN_DEV_CFG_1);447cs2000_write(chip, CS2000_DEV_CFG_2,448(0 << CS2000_LOCK_CLK_SHIFT) |449CS2000_FRAC_N_SRC_STATIC);450cs2000_write(chip, CS2000_RATIO_0 + 0, 0x00); /* 1.0 */451cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10);452cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00);453cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00);454cs2000_write(chip, CS2000_FUN_CFG_1,455data->cs2000_regs[CS2000_FUN_CFG_1]);456cs2000_write(chip, CS2000_FUN_CFG_2, 0);457cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2);458msleep(3); /* PLL lock delay */459}460461static void xonar_st_init(struct oxygen *chip)462{463struct xonar_pcm179x *data = chip->model_data;464465data->generic.anti_pop_delay = 100;466data->h6 = chip->model.dac_channels_mixer > 2;467data->has_cs2000 = 1;468data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;469data->broken_i2c = true;470471oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,472OXYGEN_RATE_48000 |473OXYGEN_I2S_FORMAT_I2S |474OXYGEN_I2S_MCLK(data->h6 ? MCLK_256 : MCLK_512) |475OXYGEN_I2S_BITS_16 |476OXYGEN_I2S_MASTER |477OXYGEN_I2S_BCLK_64);478479xonar_st_init_i2c(chip);480cs2000_registers_init(chip);481xonar_st_init_common(chip);482483snd_component_add(chip->card, "CS2000");484}485486static void xonar_stx_init(struct oxygen *chip)487{488struct xonar_pcm179x *data = chip->model_data;489490xonar_st_init_i2c(chip);491data->generic.anti_pop_delay = 800;492data->generic.ext_power_reg = OXYGEN_GPI_DATA;493data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;494data->generic.ext_power_bit = GPI_EXT_POWER;495xonar_init_ext_power(chip);496xonar_st_init_common(chip);497}498499static void xonar_d2_cleanup(struct oxygen *chip)500{501xonar_disable_output(chip);502}503504static void xonar_hdav_cleanup(struct oxygen *chip)505{506xonar_hdmi_cleanup(chip);507xonar_disable_output(chip);508msleep(2);509}510511static void xonar_st_cleanup(struct oxygen *chip)512{513xonar_disable_output(chip);514}515516static void xonar_d2_suspend(struct oxygen *chip)517{518xonar_d2_cleanup(chip);519}520521static void xonar_hdav_suspend(struct oxygen *chip)522{523xonar_hdav_cleanup(chip);524}525526static void xonar_st_suspend(struct oxygen *chip)527{528xonar_st_cleanup(chip);529}530531static void xonar_d2_resume(struct oxygen *chip)532{533pcm1796_registers_init(chip);534xonar_enable_output(chip);535}536537static void xonar_hdav_resume(struct oxygen *chip)538{539struct xonar_hdav *data = chip->model_data;540541pcm1796_registers_init(chip);542xonar_hdmi_resume(chip, &data->hdmi);543xonar_enable_output(chip);544}545546static void xonar_stx_resume(struct oxygen *chip)547{548pcm1796_registers_init(chip);549xonar_enable_output(chip);550}551552static void xonar_st_resume(struct oxygen *chip)553{554cs2000_registers_init(chip);555xonar_stx_resume(chip);556}557558static void update_pcm1796_oversampling(struct oxygen *chip)559{560struct xonar_pcm179x *data = chip->model_data;561unsigned int i;562u8 reg;563564if (data->current_rate <= 48000 && !data->h6)565reg = PCM1796_OS_128;566else567reg = PCM1796_OS_64;568for (i = 0; i < data->dacs; ++i)569pcm1796_write_cached(chip, i, 20, reg);570}571572static void set_pcm1796_params(struct oxygen *chip,573struct snd_pcm_hw_params *params)574{575struct xonar_pcm179x *data = chip->model_data;576577msleep(1);578data->current_rate = params_rate(params);579update_pcm1796_oversampling(chip);580}581582static void update_pcm1796_volume(struct oxygen *chip)583{584struct xonar_pcm179x *data = chip->model_data;585unsigned int i;586s8 gain_offset;587588gain_offset = data->hp_active ? data->hp_gain_offset : 0;589for (i = 0; i < data->dacs; ++i) {590pcm1796_write_cached(chip, i, 16, chip->dac_volume[i * 2]591+ gain_offset);592pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1]593+ gain_offset);594gain_offset = 0;595}596}597598static void update_pcm1796_mute(struct oxygen *chip)599{600struct xonar_pcm179x *data = chip->model_data;601unsigned int i;602u8 value;603604value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;605if (chip->dac_mute)606value |= PCM1796_MUTE;607for (i = 0; i < data->dacs; ++i)608pcm1796_write_cached(chip, i, 18, value);609}610611static void update_cs2000_rate(struct oxygen *chip, unsigned int rate)612{613struct xonar_pcm179x *data = chip->model_data;614u8 rate_mclk, reg;615616switch (rate) {617case 32000:618case 64000:619rate_mclk = OXYGEN_RATE_32000;620break;621case 44100:622case 88200:623case 176400:624rate_mclk = OXYGEN_RATE_44100;625break;626default:627case 48000:628case 96000:629case 192000:630rate_mclk = OXYGEN_RATE_48000;631break;632}633634if (rate <= 96000 && (rate > 48000 || data->h6)) {635rate_mclk |= OXYGEN_I2S_MCLK(MCLK_256);636reg = CS2000_REF_CLK_DIV_1;637} else {638rate_mclk |= OXYGEN_I2S_MCLK(MCLK_512);639reg = CS2000_REF_CLK_DIV_2;640}641642oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,643OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);644cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg);645msleep(3); /* PLL lock delay */646}647648static void set_st_params(struct oxygen *chip,649struct snd_pcm_hw_params *params)650{651update_cs2000_rate(chip, params_rate(params));652set_pcm1796_params(chip, params);653}654655static void set_hdav_params(struct oxygen *chip,656struct snd_pcm_hw_params *params)657{658struct xonar_hdav *data = chip->model_data;659660set_pcm1796_params(chip, params);661xonar_set_hdmi_params(chip, &data->hdmi, params);662}663664static const struct snd_kcontrol_new alt_switch = {665.iface = SNDRV_CTL_ELEM_IFACE_MIXER,666.name = "Analog Loopback Switch",667.info = snd_ctl_boolean_mono_info,668.get = xonar_gpio_bit_switch_get,669.put = xonar_gpio_bit_switch_put,670.private_value = GPIO_D2_ALT,671};672673static int rolloff_info(struct snd_kcontrol *ctl,674struct snd_ctl_elem_info *info)675{676static const char *const names[2] = {677"Sharp Roll-off", "Slow Roll-off"678};679680return snd_ctl_enum_info(info, 1, 2, names);681}682683static int rolloff_get(struct snd_kcontrol *ctl,684struct snd_ctl_elem_value *value)685{686struct oxygen *chip = ctl->private_data;687struct xonar_pcm179x *data = chip->model_data;688689value->value.enumerated.item[0] =690(data->pcm1796_regs[0][19 - PCM1796_REG_BASE] &691PCM1796_FLT_MASK) != PCM1796_FLT_SHARP;692return 0;693}694695static int rolloff_put(struct snd_kcontrol *ctl,696struct snd_ctl_elem_value *value)697{698struct oxygen *chip = ctl->private_data;699struct xonar_pcm179x *data = chip->model_data;700unsigned int i;701int changed;702u8 reg;703704mutex_lock(&chip->mutex);705reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE];706reg &= ~PCM1796_FLT_MASK;707if (!value->value.enumerated.item[0])708reg |= PCM1796_FLT_SHARP;709else710reg |= PCM1796_FLT_SLOW;711changed = reg != data->pcm1796_regs[0][19 - PCM1796_REG_BASE];712if (changed) {713for (i = 0; i < data->dacs; ++i)714pcm1796_write(chip, i, 19, reg);715}716mutex_unlock(&chip->mutex);717return changed;718}719720static const struct snd_kcontrol_new rolloff_control = {721.iface = SNDRV_CTL_ELEM_IFACE_MIXER,722.name = "DAC Filter Playback Enum",723.info = rolloff_info,724.get = rolloff_get,725.put = rolloff_put,726};727728static const struct snd_kcontrol_new hdav_hdmi_control = {729.iface = SNDRV_CTL_ELEM_IFACE_MIXER,730.name = "HDMI Playback Switch",731.info = snd_ctl_boolean_mono_info,732.get = xonar_gpio_bit_switch_get,733.put = xonar_gpio_bit_switch_put,734.private_value = GPIO_HDAV_OUTPUT_ENABLE | XONAR_GPIO_BIT_INVERT,735};736737static int st_output_switch_info(struct snd_kcontrol *ctl,738struct snd_ctl_elem_info *info)739{740static const char *const names[3] = {741"Speakers", "Headphones", "FP Headphones"742};743744return snd_ctl_enum_info(info, 1, 3, names);745}746747static int st_output_switch_get(struct snd_kcontrol *ctl,748struct snd_ctl_elem_value *value)749{750struct oxygen *chip = ctl->private_data;751u16 gpio;752753gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);754if (!(gpio & GPIO_ST_HP))755value->value.enumerated.item[0] = 0;756else if (gpio & GPIO_ST_HP_REAR)757value->value.enumerated.item[0] = 1;758else759value->value.enumerated.item[0] = 2;760return 0;761}762763764static int st_output_switch_put(struct snd_kcontrol *ctl,765struct snd_ctl_elem_value *value)766{767struct oxygen *chip = ctl->private_data;768struct xonar_pcm179x *data = chip->model_data;769u16 gpio_old, gpio;770771mutex_lock(&chip->mutex);772gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);773gpio = gpio_old;774switch (value->value.enumerated.item[0]) {775case 0:776gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR);777break;778case 1:779gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR;780break;781case 2:782gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR;783break;784}785oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);786data->hp_active = gpio & GPIO_ST_HP;787update_pcm1796_volume(chip);788mutex_unlock(&chip->mutex);789return gpio != gpio_old;790}791792static int st_hp_volume_offset_info(struct snd_kcontrol *ctl,793struct snd_ctl_elem_info *info)794{795static const char *const names[3] = {796"< 64 ohms", "64-300 ohms", "300-600 ohms"797};798799return snd_ctl_enum_info(info, 1, 3, names);800}801802static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,803struct snd_ctl_elem_value *value)804{805struct oxygen *chip = ctl->private_data;806struct xonar_pcm179x *data = chip->model_data;807808mutex_lock(&chip->mutex);809if (data->hp_gain_offset < 2*-6)810value->value.enumerated.item[0] = 0;811else if (data->hp_gain_offset < 0)812value->value.enumerated.item[0] = 1;813else814value->value.enumerated.item[0] = 2;815mutex_unlock(&chip->mutex);816return 0;817}818819820static int st_hp_volume_offset_put(struct snd_kcontrol *ctl,821struct snd_ctl_elem_value *value)822{823static const s8 offsets[] = { 2*-18, 2*-6, 0 };824struct oxygen *chip = ctl->private_data;825struct xonar_pcm179x *data = chip->model_data;826s8 offset;827int changed;828829if (value->value.enumerated.item[0] > 2)830return -EINVAL;831offset = offsets[value->value.enumerated.item[0]];832mutex_lock(&chip->mutex);833changed = offset != data->hp_gain_offset;834if (changed) {835data->hp_gain_offset = offset;836update_pcm1796_volume(chip);837}838mutex_unlock(&chip->mutex);839return changed;840}841842static const struct snd_kcontrol_new st_controls[] = {843{844.iface = SNDRV_CTL_ELEM_IFACE_MIXER,845.name = "Analog Output",846.info = st_output_switch_info,847.get = st_output_switch_get,848.put = st_output_switch_put,849},850{851.iface = SNDRV_CTL_ELEM_IFACE_MIXER,852.name = "Headphones Impedance Playback Enum",853.info = st_hp_volume_offset_info,854.get = st_hp_volume_offset_get,855.put = st_hp_volume_offset_put,856},857};858859static void xonar_line_mic_ac97_switch(struct oxygen *chip,860unsigned int reg, unsigned int mute)861{862if (reg == AC97_LINE) {863spin_lock_irq(&chip->reg_lock);864oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,865mute ? GPIO_INPUT_ROUTE : 0,866GPIO_INPUT_ROUTE);867spin_unlock_irq(&chip->reg_lock);868}869}870871static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);872873static int xonar_d2_control_filter(struct snd_kcontrol_new *template)874{875if (!strncmp(template->name, "CD Capture ", 11))876/* CD in is actually connected to the video in pin */877template->private_value ^= AC97_CD ^ AC97_VIDEO;878return 0;879}880881static int xonar_st_h6_control_filter(struct snd_kcontrol_new *template)882{883if (!strncmp(template->name, "Master Playback ", 16))884/* no volume/mute, as I²C to the third DAC does not work */885return 1;886return 0;887}888889static int add_pcm1796_controls(struct oxygen *chip)890{891struct xonar_pcm179x *data = chip->model_data;892int err;893894if (!data->broken_i2c) {895err = snd_ctl_add(chip->card,896snd_ctl_new1(&rolloff_control, chip));897if (err < 0)898return err;899}900return 0;901}902903static int xonar_d2_mixer_init(struct oxygen *chip)904{905int err;906907err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));908if (err < 0)909return err;910err = add_pcm1796_controls(chip);911if (err < 0)912return err;913return 0;914}915916static int xonar_hdav_mixer_init(struct oxygen *chip)917{918int err;919920err = snd_ctl_add(chip->card, snd_ctl_new1(&hdav_hdmi_control, chip));921if (err < 0)922return err;923err = add_pcm1796_controls(chip);924if (err < 0)925return err;926return 0;927}928929static int xonar_st_mixer_init(struct oxygen *chip)930{931unsigned int i;932int err;933934for (i = 0; i < ARRAY_SIZE(st_controls); ++i) {935err = snd_ctl_add(chip->card,936snd_ctl_new1(&st_controls[i], chip));937if (err < 0)938return err;939}940err = add_pcm1796_controls(chip);941if (err < 0)942return err;943return 0;944}945946static void dump_pcm1796_registers(struct oxygen *chip,947struct snd_info_buffer *buffer)948{949struct xonar_pcm179x *data = chip->model_data;950unsigned int dac, i;951952for (dac = 0; dac < data->dacs; ++dac) {953snd_iprintf(buffer, "\nPCM1796 %u:", dac + 1);954for (i = 0; i < 5; ++i)955snd_iprintf(buffer, " %02x",956data->pcm1796_regs[dac][i]);957}958snd_iprintf(buffer, "\n");959}960961static void dump_cs2000_registers(struct oxygen *chip,962struct snd_info_buffer *buffer)963{964struct xonar_pcm179x *data = chip->model_data;965unsigned int i;966967if (data->has_cs2000) {968snd_iprintf(buffer, "\nCS2000:\n00: ");969for (i = 1; i < 0x10; ++i)970snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);971snd_iprintf(buffer, "\n10:");972for (i = 0x10; i < 0x1f; ++i)973snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);974snd_iprintf(buffer, "\n");975}976}977978static void dump_st_registers(struct oxygen *chip,979struct snd_info_buffer *buffer)980{981dump_pcm1796_registers(chip, buffer);982dump_cs2000_registers(chip, buffer);983}984985static const struct oxygen_model model_xonar_d2 = {986.longname = "Asus Virtuoso 200",987.chip = "AV200",988.init = xonar_d2_init,989.control_filter = xonar_d2_control_filter,990.mixer_init = xonar_d2_mixer_init,991.cleanup = xonar_d2_cleanup,992.suspend = xonar_d2_suspend,993.resume = xonar_d2_resume,994.set_dac_params = set_pcm1796_params,995.set_adc_params = xonar_set_cs53x1_params,996.update_dac_volume = update_pcm1796_volume,997.update_dac_mute = update_pcm1796_mute,998.dump_registers = dump_pcm1796_registers,999.dac_tlv = pcm1796_db_scale,1000.model_data_size = sizeof(struct xonar_pcm179x),1001.device_config = PLAYBACK_0_TO_I2S |1002PLAYBACK_1_TO_SPDIF |1003CAPTURE_0_FROM_I2S_2 |1004CAPTURE_1_FROM_SPDIF |1005MIDI_OUTPUT |1006MIDI_INPUT |1007AC97_CD_INPUT,1008.dac_channels_pcm = 8,1009.dac_channels_mixer = 8,1010.dac_volume_min = 255 - 2*60,1011.dac_volume_max = 255,1012.misc_flags = OXYGEN_MISC_MIDI,1013.function_flags = OXYGEN_FUNCTION_SPI |1014OXYGEN_FUNCTION_ENABLE_SPI_4_5,1015.dac_mclks = OXYGEN_MCLKS(512, 128, 128),1016.adc_mclks = OXYGEN_MCLKS(256, 128, 128),1017.dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,1018.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,1019};10201021static const struct oxygen_model model_xonar_hdav = {1022.longname = "Asus Virtuoso 200",1023.chip = "AV200",1024.init = xonar_hdav_init,1025.mixer_init = xonar_hdav_mixer_init,1026.cleanup = xonar_hdav_cleanup,1027.suspend = xonar_hdav_suspend,1028.resume = xonar_hdav_resume,1029.pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter,1030.set_dac_params = set_hdav_params,1031.set_adc_params = xonar_set_cs53x1_params,1032.update_dac_volume = update_pcm1796_volume,1033.update_dac_mute = update_pcm1796_mute,1034.uart_input = xonar_hdmi_uart_input,1035.ac97_switch = xonar_line_mic_ac97_switch,1036.dump_registers = dump_pcm1796_registers,1037.dac_tlv = pcm1796_db_scale,1038.model_data_size = sizeof(struct xonar_hdav),1039.device_config = PLAYBACK_0_TO_I2S |1040PLAYBACK_1_TO_SPDIF |1041CAPTURE_0_FROM_I2S_2 |1042CAPTURE_1_FROM_SPDIF,1043.dac_channels_pcm = 8,1044.dac_channels_mixer = 2,1045.dac_volume_min = 255 - 2*60,1046.dac_volume_max = 255,1047.misc_flags = OXYGEN_MISC_MIDI,1048.function_flags = OXYGEN_FUNCTION_2WIRE,1049.dac_mclks = OXYGEN_MCLKS(512, 128, 128),1050.adc_mclks = OXYGEN_MCLKS(256, 128, 128),1051.dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,1052.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,1053};10541055static const struct oxygen_model model_xonar_st = {1056.longname = "Asus Virtuoso 100",1057.chip = "AV200",1058.init = xonar_st_init,1059.mixer_init = xonar_st_mixer_init,1060.cleanup = xonar_st_cleanup,1061.suspend = xonar_st_suspend,1062.resume = xonar_st_resume,1063.set_dac_params = set_st_params,1064.set_adc_params = xonar_set_cs53x1_params,1065.update_dac_volume = update_pcm1796_volume,1066.update_dac_mute = update_pcm1796_mute,1067.ac97_switch = xonar_line_mic_ac97_switch,1068.dump_registers = dump_st_registers,1069.dac_tlv = pcm1796_db_scale,1070.model_data_size = sizeof(struct xonar_pcm179x),1071.device_config = PLAYBACK_0_TO_I2S |1072PLAYBACK_1_TO_SPDIF |1073CAPTURE_0_FROM_I2S_2 |1074AC97_FMIC_SWITCH,1075.dac_channels_pcm = 2,1076.dac_channels_mixer = 2,1077.dac_volume_min = 255 - 2*60,1078.dac_volume_max = 255,1079.function_flags = OXYGEN_FUNCTION_2WIRE,1080.dac_mclks = OXYGEN_MCLKS(512, 128, 128),1081.adc_mclks = OXYGEN_MCLKS(256, 128, 128),1082.dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,1083.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,1084};10851086int __devinit get_xonar_pcm179x_model(struct oxygen *chip,1087const struct pci_device_id *id)1088{1089switch (id->subdevice) {1090case 0x8269:1091chip->model = model_xonar_d2;1092chip->model.shortname = "Xonar D2";1093break;1094case 0x82b7:1095chip->model = model_xonar_d2;1096chip->model.shortname = "Xonar D2X";1097chip->model.init = xonar_d2x_init;1098break;1099case 0x8314:1100chip->model = model_xonar_hdav;1101oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);1102switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {1103default:1104chip->model.shortname = "Xonar HDAV1.3";1105break;1106case GPIO_DB_H6:1107chip->model.shortname = "Xonar HDAV1.3+H6";1108chip->model.dac_channels_mixer = 8;1109chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);1110break;1111}1112break;1113case 0x835d:1114chip->model = model_xonar_st;1115oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);1116switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {1117default:1118chip->model.shortname = "Xonar ST";1119break;1120case GPIO_DB_H6:1121chip->model.shortname = "Xonar ST+H6";1122chip->model.control_filter = xonar_st_h6_control_filter;1123chip->model.dac_channels_pcm = 8;1124chip->model.dac_channels_mixer = 8;1125chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);1126break;1127}1128break;1129case 0x835c:1130chip->model = model_xonar_st;1131chip->model.shortname = "Xonar STX";1132chip->model.init = xonar_stx_init;1133chip->model.resume = xonar_stx_resume;1134chip->model.set_dac_params = set_pcm1796_params;1135break;1136default:1137return -EINVAL;1138}1139return 0;1140}114111421143