165c3ac88SClemens Ladisch /* 265c3ac88SClemens Ladisch * card driver for models with CS4398/CS4362A DACs (Xonar D1/DX) 365c3ac88SClemens Ladisch * 465c3ac88SClemens Ladisch * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 565c3ac88SClemens Ladisch * 665c3ac88SClemens Ladisch * 765c3ac88SClemens Ladisch * This driver is free software; you can redistribute it and/or modify 865c3ac88SClemens Ladisch * it under the terms of the GNU General Public License, version 2. 965c3ac88SClemens Ladisch * 1065c3ac88SClemens Ladisch * This driver is distributed in the hope that it will be useful, 1165c3ac88SClemens Ladisch * but WITHOUT ANY WARRANTY; without even the implied warranty of 1265c3ac88SClemens Ladisch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1365c3ac88SClemens Ladisch * GNU General Public License for more details. 1465c3ac88SClemens Ladisch * 1565c3ac88SClemens Ladisch * You should have received a copy of the GNU General Public License 1665c3ac88SClemens Ladisch * along with this driver; if not, see <http://www.gnu.org/licenses/>. 1765c3ac88SClemens Ladisch */ 1865c3ac88SClemens Ladisch 1965c3ac88SClemens Ladisch /* 2065c3ac88SClemens Ladisch * Xonar D1/DX 2165c3ac88SClemens Ladisch * ----------- 2265c3ac88SClemens Ladisch * 2365c3ac88SClemens Ladisch * CMI8788: 2465c3ac88SClemens Ladisch * 2565c3ac88SClemens Ladisch * I²C <-> CS4398 (front) 2665c3ac88SClemens Ladisch * <-> CS4362A (surround, center/LFE, back) 2765c3ac88SClemens Ladisch * 2865c3ac88SClemens Ladisch * GPI 0 <- external power present (DX only) 2965c3ac88SClemens Ladisch * 3065c3ac88SClemens Ladisch * GPIO 0 -> enable output to speakers 3165c3ac88SClemens Ladisch * GPIO 1 -> enable front panel I/O 3265c3ac88SClemens Ladisch * GPIO 2 -> M0 of CS5361 3365c3ac88SClemens Ladisch * GPIO 3 -> M1 of CS5361 3465c3ac88SClemens Ladisch * GPIO 8 -> route input jack to line-in (0) or mic-in (1) 3565c3ac88SClemens Ladisch * 3665c3ac88SClemens Ladisch * CS4398: 3765c3ac88SClemens Ladisch * 3865c3ac88SClemens Ladisch * AD0 <- 1 3965c3ac88SClemens Ladisch * AD1 <- 1 4065c3ac88SClemens Ladisch * 4165c3ac88SClemens Ladisch * CS4362A: 4265c3ac88SClemens Ladisch * 4365c3ac88SClemens Ladisch * AD0 <- 0 44dc0adf48SClemens Ladisch * 45dc0adf48SClemens Ladisch * CM9780: 46dc0adf48SClemens Ladisch * 47dc0adf48SClemens Ladisch * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input 4865c3ac88SClemens Ladisch */ 4965c3ac88SClemens Ladisch 5065c3ac88SClemens Ladisch #include <linux/pci.h> 5165c3ac88SClemens Ladisch #include <linux/delay.h> 5265c3ac88SClemens Ladisch #include <sound/ac97_codec.h> 5365c3ac88SClemens Ladisch #include <sound/control.h> 5465c3ac88SClemens Ladisch #include <sound/core.h> 5565c3ac88SClemens Ladisch #include <sound/pcm.h> 5665c3ac88SClemens Ladisch #include <sound/pcm_params.h> 5765c3ac88SClemens Ladisch #include <sound/tlv.h> 5865c3ac88SClemens Ladisch #include "xonar.h" 596a45f782SClemens Ladisch #include "cm9780.h" 6065c3ac88SClemens Ladisch #include "cs4398.h" 6165c3ac88SClemens Ladisch #include "cs4362a.h" 6265c3ac88SClemens Ladisch 6365c3ac88SClemens Ladisch #define GPI_EXT_POWER 0x01 6465c3ac88SClemens Ladisch #define GPIO_D1_OUTPUT_ENABLE 0x0001 6565c3ac88SClemens Ladisch #define GPIO_D1_FRONT_PANEL 0x0002 66*f7e4bad7SClemens Ladisch #define GPIO_D1_MAGIC 0x00c0 6765c3ac88SClemens Ladisch #define GPIO_D1_INPUT_ROUTE 0x0100 6865c3ac88SClemens Ladisch 6965c3ac88SClemens Ladisch #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ 7065c3ac88SClemens Ladisch #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ 7165c3ac88SClemens Ladisch 7265c3ac88SClemens Ladisch struct xonar_cs43xx { 7365c3ac88SClemens Ladisch struct xonar_generic generic; 744852ad02SClemens Ladisch u8 cs4398_regs[8]; 756f0de3ceSClemens Ladisch u8 cs4362a_regs[15]; 7665c3ac88SClemens Ladisch }; 7765c3ac88SClemens Ladisch 7865c3ac88SClemens Ladisch static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) 7965c3ac88SClemens Ladisch { 806f0de3ceSClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 816f0de3ceSClemens Ladisch 8265c3ac88SClemens Ladisch oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value); 836f0de3ceSClemens Ladisch if (reg < ARRAY_SIZE(data->cs4398_regs)) 846f0de3ceSClemens Ladisch data->cs4398_regs[reg] = value; 856f0de3ceSClemens Ladisch } 866f0de3ceSClemens Ladisch 876f0de3ceSClemens Ladisch static void cs4398_write_cached(struct oxygen *chip, u8 reg, u8 value) 886f0de3ceSClemens Ladisch { 896f0de3ceSClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 906f0de3ceSClemens Ladisch 916f0de3ceSClemens Ladisch if (value != data->cs4398_regs[reg]) 926f0de3ceSClemens Ladisch cs4398_write(chip, reg, value); 9365c3ac88SClemens Ladisch } 9465c3ac88SClemens Ladisch 9565c3ac88SClemens Ladisch static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) 9665c3ac88SClemens Ladisch { 976f0de3ceSClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 986f0de3ceSClemens Ladisch 9965c3ac88SClemens Ladisch oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); 1006f0de3ceSClemens Ladisch if (reg < ARRAY_SIZE(data->cs4362a_regs)) 1016f0de3ceSClemens Ladisch data->cs4362a_regs[reg] = value; 10265c3ac88SClemens Ladisch } 10365c3ac88SClemens Ladisch 1046f0de3ceSClemens Ladisch static void cs4362a_write_cached(struct oxygen *chip, u8 reg, u8 value) 10565c3ac88SClemens Ladisch { 10665c3ac88SClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 10765c3ac88SClemens Ladisch 1086f0de3ceSClemens Ladisch if (value != data->cs4362a_regs[reg]) 1096f0de3ceSClemens Ladisch cs4362a_write(chip, reg, value); 1106f0de3ceSClemens Ladisch } 1116f0de3ceSClemens Ladisch 1126f0de3ceSClemens Ladisch static void cs43xx_registers_init(struct oxygen *chip) 1136f0de3ceSClemens Ladisch { 1146f0de3ceSClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 1156f0de3ceSClemens Ladisch unsigned int i; 1166f0de3ceSClemens Ladisch 11765c3ac88SClemens Ladisch /* set CPEN (control port mode) and power down */ 11865c3ac88SClemens Ladisch cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); 11965c3ac88SClemens Ladisch cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); 12065c3ac88SClemens Ladisch /* configure */ 1216f0de3ceSClemens Ladisch cs4398_write(chip, 2, data->cs4398_regs[2]); 12265c3ac88SClemens Ladisch cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); 1236f0de3ceSClemens Ladisch cs4398_write(chip, 4, data->cs4398_regs[4]); 1246f0de3ceSClemens Ladisch cs4398_write(chip, 5, data->cs4398_regs[5]); 1256f0de3ceSClemens Ladisch cs4398_write(chip, 6, data->cs4398_regs[6]); 1264852ad02SClemens Ladisch cs4398_write(chip, 7, data->cs4398_regs[7]); 12765c3ac88SClemens Ladisch cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); 12865c3ac88SClemens Ladisch cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | 12965c3ac88SClemens Ladisch CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); 1304852ad02SClemens Ladisch cs4362a_write(chip, 0x04, data->cs4362a_regs[0x04]); 13165c3ac88SClemens Ladisch cs4362a_write(chip, 0x05, 0); 1326f0de3ceSClemens Ladisch for (i = 6; i <= 14; ++i) 1336f0de3ceSClemens Ladisch cs4362a_write(chip, i, data->cs4362a_regs[i]); 13465c3ac88SClemens Ladisch /* clear power down */ 13565c3ac88SClemens Ladisch cs4398_write(chip, 8, CS4398_CPEN); 13665c3ac88SClemens Ladisch cs4362a_write(chip, 0x01, CS4362A_CPEN); 13765c3ac88SClemens Ladisch } 13865c3ac88SClemens Ladisch 13965c3ac88SClemens Ladisch static void xonar_d1_init(struct oxygen *chip) 14065c3ac88SClemens Ladisch { 14165c3ac88SClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 14265c3ac88SClemens Ladisch 14365c3ac88SClemens Ladisch data->generic.anti_pop_delay = 800; 14465c3ac88SClemens Ladisch data->generic.output_enable_bit = GPIO_D1_OUTPUT_ENABLE; 1456f0de3ceSClemens Ladisch data->cs4398_regs[2] = 1466f0de3ceSClemens Ladisch CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; 1476f0de3ceSClemens Ladisch data->cs4398_regs[4] = CS4398_MUTEP_LOW | 1486f0de3ceSClemens Ladisch CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE; 1496f0de3ceSClemens Ladisch data->cs4398_regs[5] = 60 * 2; 1506f0de3ceSClemens Ladisch data->cs4398_regs[6] = 60 * 2; 1514852ad02SClemens Ladisch data->cs4398_regs[7] = CS4398_RMP_DN | CS4398_RMP_UP | 1524852ad02SClemens Ladisch CS4398_ZERO_CROSS | CS4398_SOFT_RAMP; 1534852ad02SClemens Ladisch data->cs4362a_regs[4] = CS4362A_RMP_DN | CS4362A_DEM_NONE; 1546f0de3ceSClemens Ladisch data->cs4362a_regs[6] = CS4362A_FM_SINGLE | 15565c3ac88SClemens Ladisch CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; 1566f0de3ceSClemens Ladisch data->cs4362a_regs[7] = 60 | CS4362A_MUTE; 1576f0de3ceSClemens Ladisch data->cs4362a_regs[8] = 60 | CS4362A_MUTE; 1586f0de3ceSClemens Ladisch data->cs4362a_regs[9] = data->cs4362a_regs[6]; 1596f0de3ceSClemens Ladisch data->cs4362a_regs[10] = 60 | CS4362A_MUTE; 1606f0de3ceSClemens Ladisch data->cs4362a_regs[11] = 60 | CS4362A_MUTE; 1616f0de3ceSClemens Ladisch data->cs4362a_regs[12] = data->cs4362a_regs[6]; 1626f0de3ceSClemens Ladisch data->cs4362a_regs[13] = 60 | CS4362A_MUTE; 1636f0de3ceSClemens Ladisch data->cs4362a_regs[14] = 60 | CS4362A_MUTE; 16465c3ac88SClemens Ladisch 16565c3ac88SClemens Ladisch oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, 16665c3ac88SClemens Ladisch OXYGEN_2WIRE_LENGTH_8 | 16765c3ac88SClemens Ladisch OXYGEN_2WIRE_INTERRUPT_MASK | 16865c3ac88SClemens Ladisch OXYGEN_2WIRE_SPEED_FAST); 16965c3ac88SClemens Ladisch 1706f0de3ceSClemens Ladisch cs43xx_registers_init(chip); 17165c3ac88SClemens Ladisch 17265c3ac88SClemens Ladisch oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, 173*f7e4bad7SClemens Ladisch GPIO_D1_FRONT_PANEL | 174*f7e4bad7SClemens Ladisch GPIO_D1_MAGIC | 175*f7e4bad7SClemens Ladisch GPIO_D1_INPUT_ROUTE); 17665c3ac88SClemens Ladisch oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, 17765c3ac88SClemens Ladisch GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); 17865c3ac88SClemens Ladisch 1796a45f782SClemens Ladisch oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); 1806a45f782SClemens Ladisch 18165c3ac88SClemens Ladisch xonar_init_cs53x1(chip); 18265c3ac88SClemens Ladisch xonar_enable_output(chip); 18365c3ac88SClemens Ladisch 18465c3ac88SClemens Ladisch snd_component_add(chip->card, "CS4398"); 18565c3ac88SClemens Ladisch snd_component_add(chip->card, "CS4362A"); 18665c3ac88SClemens Ladisch snd_component_add(chip->card, "CS5361"); 18765c3ac88SClemens Ladisch } 18865c3ac88SClemens Ladisch 18965c3ac88SClemens Ladisch static void xonar_dx_init(struct oxygen *chip) 19065c3ac88SClemens Ladisch { 19165c3ac88SClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 19265c3ac88SClemens Ladisch 19365c3ac88SClemens Ladisch data->generic.ext_power_reg = OXYGEN_GPI_DATA; 19465c3ac88SClemens Ladisch data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; 19565c3ac88SClemens Ladisch data->generic.ext_power_bit = GPI_EXT_POWER; 19665c3ac88SClemens Ladisch xonar_init_ext_power(chip); 19765c3ac88SClemens Ladisch xonar_d1_init(chip); 19865c3ac88SClemens Ladisch } 19965c3ac88SClemens Ladisch 20065c3ac88SClemens Ladisch static void xonar_d1_cleanup(struct oxygen *chip) 20165c3ac88SClemens Ladisch { 20265c3ac88SClemens Ladisch xonar_disable_output(chip); 20365c3ac88SClemens Ladisch cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); 20465c3ac88SClemens Ladisch oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); 20565c3ac88SClemens Ladisch } 20665c3ac88SClemens Ladisch 20765c3ac88SClemens Ladisch static void xonar_d1_suspend(struct oxygen *chip) 20865c3ac88SClemens Ladisch { 20965c3ac88SClemens Ladisch xonar_d1_cleanup(chip); 21065c3ac88SClemens Ladisch } 21165c3ac88SClemens Ladisch 21265c3ac88SClemens Ladisch static void xonar_d1_resume(struct oxygen *chip) 21365c3ac88SClemens Ladisch { 21465c3ac88SClemens Ladisch oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); 21565c3ac88SClemens Ladisch msleep(1); 2166f0de3ceSClemens Ladisch cs43xx_registers_init(chip); 21765c3ac88SClemens Ladisch xonar_enable_output(chip); 21865c3ac88SClemens Ladisch } 21965c3ac88SClemens Ladisch 22065c3ac88SClemens Ladisch static void set_cs43xx_params(struct oxygen *chip, 22165c3ac88SClemens Ladisch struct snd_pcm_hw_params *params) 22265c3ac88SClemens Ladisch { 22365c3ac88SClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 2243d8bb454SClemens Ladisch u8 cs4398_fm, cs4362a_fm; 22565c3ac88SClemens Ladisch 22665c3ac88SClemens Ladisch if (params_rate(params) <= 50000) { 2273d8bb454SClemens Ladisch cs4398_fm = CS4398_FM_SINGLE; 2283d8bb454SClemens Ladisch cs4362a_fm = CS4362A_FM_SINGLE; 22965c3ac88SClemens Ladisch } else if (params_rate(params) <= 100000) { 2303d8bb454SClemens Ladisch cs4398_fm = CS4398_FM_DOUBLE; 2313d8bb454SClemens Ladisch cs4362a_fm = CS4362A_FM_DOUBLE; 23265c3ac88SClemens Ladisch } else { 2333d8bb454SClemens Ladisch cs4398_fm = CS4398_FM_QUAD; 2343d8bb454SClemens Ladisch cs4362a_fm = CS4362A_FM_QUAD; 23565c3ac88SClemens Ladisch } 2366f0de3ceSClemens Ladisch cs4398_fm |= CS4398_DEM_NONE | CS4398_DIF_LJUST; 2376f0de3ceSClemens Ladisch cs4398_write_cached(chip, 2, cs4398_fm); 2386f0de3ceSClemens Ladisch cs4362a_fm |= data->cs4362a_regs[6] & ~CS4362A_FM_MASK; 2396f0de3ceSClemens Ladisch cs4362a_write_cached(chip, 6, cs4362a_fm); 2406f0de3ceSClemens Ladisch cs4362a_write_cached(chip, 12, cs4362a_fm); 2416f0de3ceSClemens Ladisch cs4362a_fm &= CS4362A_FM_MASK; 2426f0de3ceSClemens Ladisch cs4362a_fm |= data->cs4362a_regs[9] & ~CS4362A_FM_MASK; 2436f0de3ceSClemens Ladisch cs4362a_write_cached(chip, 9, cs4362a_fm); 2446f0de3ceSClemens Ladisch } 2456f0de3ceSClemens Ladisch 2466f0de3ceSClemens Ladisch static void update_cs4362a_volumes(struct oxygen *chip) 2476f0de3ceSClemens Ladisch { 2486f0de3ceSClemens Ladisch unsigned int i; 2496f0de3ceSClemens Ladisch u8 mute; 2506f0de3ceSClemens Ladisch 2516f0de3ceSClemens Ladisch mute = chip->dac_mute ? CS4362A_MUTE : 0; 2526f0de3ceSClemens Ladisch for (i = 0; i < 6; ++i) 2536f0de3ceSClemens Ladisch cs4362a_write_cached(chip, 7 + i + i / 2, 2546f0de3ceSClemens Ladisch (127 - chip->dac_volume[2 + i]) | mute); 2556f0de3ceSClemens Ladisch } 2566f0de3ceSClemens Ladisch 2576f0de3ceSClemens Ladisch static void update_cs43xx_volume(struct oxygen *chip) 2586f0de3ceSClemens Ladisch { 2596f0de3ceSClemens Ladisch cs4398_write_cached(chip, 5, (127 - chip->dac_volume[0]) * 2); 2606f0de3ceSClemens Ladisch cs4398_write_cached(chip, 6, (127 - chip->dac_volume[1]) * 2); 2616f0de3ceSClemens Ladisch update_cs4362a_volumes(chip); 2626f0de3ceSClemens Ladisch } 2636f0de3ceSClemens Ladisch 2646f0de3ceSClemens Ladisch static void update_cs43xx_mute(struct oxygen *chip) 2656f0de3ceSClemens Ladisch { 2666f0de3ceSClemens Ladisch u8 reg; 2676f0de3ceSClemens Ladisch 2686f0de3ceSClemens Ladisch reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; 2696f0de3ceSClemens Ladisch if (chip->dac_mute) 2706f0de3ceSClemens Ladisch reg |= CS4398_MUTE_B | CS4398_MUTE_A; 2716f0de3ceSClemens Ladisch cs4398_write_cached(chip, 4, reg); 2726f0de3ceSClemens Ladisch update_cs4362a_volumes(chip); 27365c3ac88SClemens Ladisch } 27465c3ac88SClemens Ladisch 2753d8bb454SClemens Ladisch static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed) 2763d8bb454SClemens Ladisch { 2773d8bb454SClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 2786f0de3ceSClemens Ladisch u8 reg; 2793d8bb454SClemens Ladisch 2806f0de3ceSClemens Ladisch reg = data->cs4362a_regs[9] & ~CS4362A_ATAPI_MASK; 2813d8bb454SClemens Ladisch if (mixed) 2826f0de3ceSClemens Ladisch reg |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR; 2833d8bb454SClemens Ladisch else 2846f0de3ceSClemens Ladisch reg |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; 2856f0de3ceSClemens Ladisch cs4362a_write_cached(chip, 9, reg); 2863d8bb454SClemens Ladisch } 2873d8bb454SClemens Ladisch 28865c3ac88SClemens Ladisch static const struct snd_kcontrol_new front_panel_switch = { 28965c3ac88SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 29065c3ac88SClemens Ladisch .name = "Front Panel Switch", 29165c3ac88SClemens Ladisch .info = snd_ctl_boolean_mono_info, 29265c3ac88SClemens Ladisch .get = xonar_gpio_bit_switch_get, 29365c3ac88SClemens Ladisch .put = xonar_gpio_bit_switch_put, 29465c3ac88SClemens Ladisch .private_value = GPIO_D1_FRONT_PANEL, 29565c3ac88SClemens Ladisch }; 29665c3ac88SClemens Ladisch 2974852ad02SClemens Ladisch static int rolloff_info(struct snd_kcontrol *ctl, 2984852ad02SClemens Ladisch struct snd_ctl_elem_info *info) 2994852ad02SClemens Ladisch { 3004852ad02SClemens Ladisch static const char *const names[2] = { 3014852ad02SClemens Ladisch "Fast Roll-off", "Slow Roll-off" 3024852ad02SClemens Ladisch }; 3034852ad02SClemens Ladisch 3044852ad02SClemens Ladisch info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 3054852ad02SClemens Ladisch info->count = 1; 3064852ad02SClemens Ladisch info->value.enumerated.items = 2; 3074852ad02SClemens Ladisch if (info->value.enumerated.item >= 2) 3084852ad02SClemens Ladisch info->value.enumerated.item = 1; 3094852ad02SClemens Ladisch strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); 3104852ad02SClemens Ladisch return 0; 3114852ad02SClemens Ladisch } 3124852ad02SClemens Ladisch 3134852ad02SClemens Ladisch static int rolloff_get(struct snd_kcontrol *ctl, 3144852ad02SClemens Ladisch struct snd_ctl_elem_value *value) 3154852ad02SClemens Ladisch { 3164852ad02SClemens Ladisch struct oxygen *chip = ctl->private_data; 3174852ad02SClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 3184852ad02SClemens Ladisch 3194852ad02SClemens Ladisch value->value.enumerated.item[0] = 3204852ad02SClemens Ladisch (data->cs4398_regs[7] & CS4398_FILT_SEL) != 0; 3214852ad02SClemens Ladisch return 0; 3224852ad02SClemens Ladisch } 3234852ad02SClemens Ladisch 3244852ad02SClemens Ladisch static int rolloff_put(struct snd_kcontrol *ctl, 3254852ad02SClemens Ladisch struct snd_ctl_elem_value *value) 3264852ad02SClemens Ladisch { 3274852ad02SClemens Ladisch struct oxygen *chip = ctl->private_data; 3284852ad02SClemens Ladisch struct xonar_cs43xx *data = chip->model_data; 3294852ad02SClemens Ladisch int changed; 3304852ad02SClemens Ladisch u8 reg; 3314852ad02SClemens Ladisch 3324852ad02SClemens Ladisch mutex_lock(&chip->mutex); 3334852ad02SClemens Ladisch reg = data->cs4398_regs[7]; 3344852ad02SClemens Ladisch if (value->value.enumerated.item[0]) 3354852ad02SClemens Ladisch reg |= CS4398_FILT_SEL; 3364852ad02SClemens Ladisch else 3374852ad02SClemens Ladisch reg &= ~CS4398_FILT_SEL; 3384852ad02SClemens Ladisch changed = reg != data->cs4398_regs[7]; 3394852ad02SClemens Ladisch if (changed) { 3404852ad02SClemens Ladisch cs4398_write(chip, 7, reg); 3414852ad02SClemens Ladisch if (reg & CS4398_FILT_SEL) 3424852ad02SClemens Ladisch reg = data->cs4362a_regs[0x04] | CS4362A_FILT_SEL; 3434852ad02SClemens Ladisch else 3444852ad02SClemens Ladisch reg = data->cs4362a_regs[0x04] & ~CS4362A_FILT_SEL; 3454852ad02SClemens Ladisch cs4362a_write(chip, 0x04, reg); 3464852ad02SClemens Ladisch } 3474852ad02SClemens Ladisch mutex_unlock(&chip->mutex); 3484852ad02SClemens Ladisch return changed; 3494852ad02SClemens Ladisch } 3504852ad02SClemens Ladisch 3514852ad02SClemens Ladisch static const struct snd_kcontrol_new rolloff_control = { 3524852ad02SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3534852ad02SClemens Ladisch .name = "DAC Filter Playback Enum", 3544852ad02SClemens Ladisch .info = rolloff_info, 3554852ad02SClemens Ladisch .get = rolloff_get, 3564852ad02SClemens Ladisch .put = rolloff_put, 3574852ad02SClemens Ladisch }; 3584852ad02SClemens Ladisch 35965c3ac88SClemens Ladisch static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, 36065c3ac88SClemens Ladisch unsigned int reg, unsigned int mute) 36165c3ac88SClemens Ladisch { 36265c3ac88SClemens Ladisch if (reg == AC97_LINE) { 36365c3ac88SClemens Ladisch spin_lock_irq(&chip->reg_lock); 36465c3ac88SClemens Ladisch oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 36565c3ac88SClemens Ladisch mute ? GPIO_D1_INPUT_ROUTE : 0, 36665c3ac88SClemens Ladisch GPIO_D1_INPUT_ROUTE); 36765c3ac88SClemens Ladisch spin_unlock_irq(&chip->reg_lock); 36865c3ac88SClemens Ladisch } 36965c3ac88SClemens Ladisch } 37065c3ac88SClemens Ladisch 37165c3ac88SClemens Ladisch static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); 37265c3ac88SClemens Ladisch 37365c3ac88SClemens Ladisch static int xonar_d1_mixer_init(struct oxygen *chip) 37465c3ac88SClemens Ladisch { 3754852ad02SClemens Ladisch int err; 3764852ad02SClemens Ladisch 3774852ad02SClemens Ladisch err = snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); 3784852ad02SClemens Ladisch if (err < 0) 3794852ad02SClemens Ladisch return err; 3804852ad02SClemens Ladisch err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); 3814852ad02SClemens Ladisch if (err < 0) 3824852ad02SClemens Ladisch return err; 3834852ad02SClemens Ladisch return 0; 38465c3ac88SClemens Ladisch } 38565c3ac88SClemens Ladisch 38665c3ac88SClemens Ladisch static const struct oxygen_model model_xonar_d1 = { 38765c3ac88SClemens Ladisch .longname = "Asus Virtuoso 100", 38865c3ac88SClemens Ladisch .chip = "AV200", 38965c3ac88SClemens Ladisch .init = xonar_d1_init, 39065c3ac88SClemens Ladisch .mixer_init = xonar_d1_mixer_init, 39165c3ac88SClemens Ladisch .cleanup = xonar_d1_cleanup, 39265c3ac88SClemens Ladisch .suspend = xonar_d1_suspend, 39365c3ac88SClemens Ladisch .resume = xonar_d1_resume, 39476ffe1e3SClemens Ladisch .get_i2s_mclk = oxygen_default_i2s_mclk, 39565c3ac88SClemens Ladisch .set_dac_params = set_cs43xx_params, 39665c3ac88SClemens Ladisch .set_adc_params = xonar_set_cs53x1_params, 39765c3ac88SClemens Ladisch .update_dac_volume = update_cs43xx_volume, 39865c3ac88SClemens Ladisch .update_dac_mute = update_cs43xx_mute, 3993d8bb454SClemens Ladisch .update_center_lfe_mix = update_cs43xx_center_lfe_mix, 40065c3ac88SClemens Ladisch .ac97_switch = xonar_d1_line_mic_ac97_switch, 40165c3ac88SClemens Ladisch .dac_tlv = cs4362a_db_scale, 40265c3ac88SClemens Ladisch .model_data_size = sizeof(struct xonar_cs43xx), 40365c3ac88SClemens Ladisch .device_config = PLAYBACK_0_TO_I2S | 40465c3ac88SClemens Ladisch PLAYBACK_1_TO_SPDIF | 40565c3ac88SClemens Ladisch CAPTURE_0_FROM_I2S_2, 40665c3ac88SClemens Ladisch .dac_channels = 8, 40765c3ac88SClemens Ladisch .dac_volume_min = 127 - 60, 40865c3ac88SClemens Ladisch .dac_volume_max = 127, 40965c3ac88SClemens Ladisch .function_flags = OXYGEN_FUNCTION_2WIRE, 41065c3ac88SClemens Ladisch .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 41165c3ac88SClemens Ladisch .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 41265c3ac88SClemens Ladisch }; 41365c3ac88SClemens Ladisch 41465c3ac88SClemens Ladisch int __devinit get_xonar_cs43xx_model(struct oxygen *chip, 41565c3ac88SClemens Ladisch const struct pci_device_id *id) 41665c3ac88SClemens Ladisch { 41765c3ac88SClemens Ladisch switch (id->subdevice) { 41865c3ac88SClemens Ladisch case 0x834f: 41965c3ac88SClemens Ladisch chip->model = model_xonar_d1; 42065c3ac88SClemens Ladisch chip->model.shortname = "Xonar D1"; 42165c3ac88SClemens Ladisch break; 42265c3ac88SClemens Ladisch case 0x8275: 42365c3ac88SClemens Ladisch case 0x8327: 42465c3ac88SClemens Ladisch chip->model = model_xonar_d1; 42565c3ac88SClemens Ladisch chip->model.shortname = "Xonar DX"; 42665c3ac88SClemens Ladisch chip->model.init = xonar_dx_init; 42765c3ac88SClemens Ladisch break; 42865c3ac88SClemens Ladisch default: 42965c3ac88SClemens Ladisch return -EINVAL; 43065c3ac88SClemens Ladisch } 43165c3ac88SClemens Ladisch return 0; 43265c3ac88SClemens Ladisch } 433