Merge branch 'xonar-dg' of git://git.alsa-project.org/alsa-kprivate into for-next

This completes the hardware support for the Asus Xonar DG/DGX cards,
and makes them actually usable.

This is v4 of Roman's patch set with some small formatting changes.

+709 -497
+1 -1
sound/pci/oxygen/Makefile
··· 1 1 snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o 2 - snd-oxygen-objs := oxygen.o xonar_dg.o 2 + snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o 3 3 snd-virtuoso-objs := virtuoso.o xonar_lib.o \ 4 4 xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o 5 5
+5 -2
sound/pci/oxygen/cs4245.h
··· 102 102 #define CS4245_ADC_OVFL 0x02 103 103 #define CS4245_ADC_UNDRFL 0x01 104 104 105 + #define CS4245_SPI_ADDRESS_S (0x9e << 16) 106 + #define CS4245_SPI_WRITE_S (0 << 16) 105 107 106 - #define CS4245_SPI_ADDRESS (0x9e << 16) 107 - #define CS4245_SPI_WRITE (0 << 16) 108 + #define CS4245_SPI_ADDRESS 0x9e 109 + #define CS4245_SPI_WRITE 0 110 + #define CS4245_SPI_READ 1
+1 -1
sound/pci/oxygen/oxygen.h
··· 198 198 void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, 199 199 unsigned int index, u16 data, u16 mask); 200 200 201 - void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data); 201 + int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data); 202 202 void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data); 203 203 204 204 void oxygen_reset_uart(struct oxygen *chip);
+19 -6
sound/pci/oxygen/oxygen_io.c
··· 194 194 } 195 195 EXPORT_SYMBOL(oxygen_write_ac97_masked); 196 196 197 - void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) 197 + static int oxygen_wait_spi(struct oxygen *chip) 198 198 { 199 199 unsigned int count; 200 200 201 - /* should not need more than 30.72 us (24 * 1.28 us) */ 202 - count = 10; 203 - while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY) 204 - && count > 0) { 201 + /* 202 + * Higher timeout to be sure: 200 us; 203 + * actual transaction should not need more than 40 us. 204 + */ 205 + for (count = 50; count > 0; count--) { 205 206 udelay(4); 206 - --count; 207 + if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & 208 + OXYGEN_SPI_BUSY) == 0) 209 + return 0; 207 210 } 211 + snd_printk(KERN_ERR "oxygen: SPI wait timeout\n"); 212 + return -EIO; 213 + } 208 214 215 + int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) 216 + { 217 + /* 218 + * We need to wait AFTER initiating the SPI transaction, 219 + * otherwise read operations will not work. 220 + */ 209 221 oxygen_write8(chip, OXYGEN_SPI_DATA1, data); 210 222 oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8); 211 223 if (control & OXYGEN_SPI_DATA_LENGTH_3) 212 224 oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16); 213 225 oxygen_write8(chip, OXYGEN_SPI_CONTROL, control); 226 + return oxygen_wait_spi(chip); 214 227 } 215 228 EXPORT_SYMBOL(oxygen_write_spi); 216 229
+1
sound/pci/oxygen/oxygen_mixer.c
··· 190 190 if (chip->model.update_center_lfe_mix) 191 191 chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2); 192 192 } 193 + EXPORT_SYMBOL(oxygen_update_dac_routing); 193 194 194 195 static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 195 196 {
+1
sound/pci/oxygen/oxygen_regs.h
··· 318 318 #define OXYGEN_PLAY_MUTE23 0x0002 319 319 #define OXYGEN_PLAY_MUTE45 0x0004 320 320 #define OXYGEN_PLAY_MUTE67 0x0008 321 + #define OXYGEN_PLAY_MUTE_MASK 0x000f 321 322 #define OXYGEN_PLAY_MULTICH_MASK 0x0010 322 323 #define OXYGEN_PLAY_MULTICH_I2S_DAC 0x0000 323 324 #define OXYGEN_PLAY_MULTICH_AC97 0x0010
+156 -487
sound/pci/oxygen/xonar_dg.c
··· 2 2 * card driver for the Xonar DG/DGX 3 3 * 4 4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 5 - * 5 + * Copyright (c) Roman Volkov <v1ron@mail.ru> 6 6 * 7 7 * This driver is free software; you can redistribute it and/or modify 8 8 * it under the terms of the GNU General Public License, version 2. ··· 20 20 * Xonar DG/DGX 21 21 * ------------ 22 22 * 23 + * CS4245 and CS4361 both will mute all outputs if any clock ratio 24 + * is invalid. 25 + * 23 26 * CMI8788: 24 27 * 25 28 * SPI 0 -> CS4245 26 29 * 30 + * Playback: 27 31 * I²S 1 -> CS4245 28 32 * I²S 2 -> CS4361 (center/LFE) 29 33 * I²S 3 -> CS4361 (surround) 30 34 * I²S 4 -> CS4361 (front) 35 + * Capture: 36 + * I²S ADC 1 <- CS4245 31 37 * 32 38 * GPIO 3 <- ? 33 39 * GPIO 4 <- headphone detect 34 - * GPIO 5 -> route input jack to line-in (0) or mic-in (1) 35 - * GPIO 6 -> route input jack to line-in (0) or mic-in (1) 36 - * GPIO 7 -> enable rear headphone amp 40 + * GPIO 5 -> enable ADC analog circuit for the left channel 41 + * GPIO 6 -> enable ADC analog circuit for the right channel 42 + * GPIO 7 -> switch green rear output jack between CS4245 and and the first 43 + * channel of CS4361 (mechanical relay) 37 44 * GPIO 8 -> enable output to speakers 38 45 * 39 46 * CS4245: 40 47 * 48 + * input 0 <- mic 41 49 * input 1 <- aux 42 50 * input 2 <- front mic 43 - * input 4 <- line/mic 51 + * input 4 <- line 44 52 * DAC out -> headphones 45 53 * aux out -> front panel headphones 46 54 */ ··· 64 56 #include "xonar_dg.h" 65 57 #include "cs4245.h" 66 58 67 - #define GPIO_MAGIC 0x0008 68 - #define GPIO_HP_DETECT 0x0010 69 - #define GPIO_INPUT_ROUTE 0x0060 70 - #define GPIO_HP_REAR 0x0080 71 - #define GPIO_OUTPUT_ENABLE 0x0100 72 - 73 - struct dg { 74 - unsigned int output_sel; 75 - s8 input_vol[4][2]; 76 - unsigned int input_sel; 77 - u8 hp_vol_att; 78 - u8 cs4245_regs[0x11]; 79 - }; 80 - 81 - static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) 59 + int cs4245_write_spi(struct oxygen *chip, u8 reg) 82 60 { 83 61 struct dg *data = chip->model_data; 62 + unsigned int packet; 84 63 85 - oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | 86 - OXYGEN_SPI_DATA_LENGTH_3 | 87 - OXYGEN_SPI_CLOCK_1280 | 88 - (0 << OXYGEN_SPI_CODEC_SHIFT) | 89 - OXYGEN_SPI_CEN_LATCH_CLOCK_HI, 90 - CS4245_SPI_ADDRESS | 91 - CS4245_SPI_WRITE | 92 - (reg << 8) | value); 93 - data->cs4245_regs[reg] = value; 64 + packet = reg << 8; 65 + packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16; 66 + packet |= data->cs4245_shadow[reg]; 67 + 68 + return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | 69 + OXYGEN_SPI_DATA_LENGTH_3 | 70 + OXYGEN_SPI_CLOCK_1280 | 71 + (0 << OXYGEN_SPI_CODEC_SHIFT) | 72 + OXYGEN_SPI_CEN_LATCH_CLOCK_HI, 73 + packet); 94 74 } 95 75 96 - static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) 76 + int cs4245_read_spi(struct oxygen *chip, u8 addr) 97 77 { 98 78 struct dg *data = chip->model_data; 79 + int ret; 99 80 100 - if (value != data->cs4245_regs[reg]) 101 - cs4245_write(chip, reg, value); 81 + ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | 82 + OXYGEN_SPI_DATA_LENGTH_2 | 83 + OXYGEN_SPI_CEN_LATCH_CLOCK_HI | 84 + OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT), 85 + ((CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 8) | addr); 86 + if (ret < 0) 87 + return ret; 88 + 89 + ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | 90 + OXYGEN_SPI_DATA_LENGTH_2 | 91 + OXYGEN_SPI_CEN_LATCH_CLOCK_HI | 92 + OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT), 93 + (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8); 94 + if (ret < 0) 95 + return ret; 96 + 97 + data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1); 98 + 99 + return 0; 102 100 } 103 101 104 - static void cs4245_registers_init(struct oxygen *chip) 102 + int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op) 105 103 { 106 104 struct dg *data = chip->model_data; 105 + unsigned char addr; 106 + int ret; 107 107 108 - cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN); 109 - cs4245_write(chip, CS4245_DAC_CTRL_1, 110 - data->cs4245_regs[CS4245_DAC_CTRL_1]); 111 - cs4245_write(chip, CS4245_ADC_CTRL, 112 - data->cs4245_regs[CS4245_ADC_CTRL]); 113 - cs4245_write(chip, CS4245_SIGNAL_SEL, 114 - data->cs4245_regs[CS4245_SIGNAL_SEL]); 115 - cs4245_write(chip, CS4245_PGA_B_CTRL, 116 - data->cs4245_regs[CS4245_PGA_B_CTRL]); 117 - cs4245_write(chip, CS4245_PGA_A_CTRL, 118 - data->cs4245_regs[CS4245_PGA_A_CTRL]); 119 - cs4245_write(chip, CS4245_ANALOG_IN, 120 - data->cs4245_regs[CS4245_ANALOG_IN]); 121 - cs4245_write(chip, CS4245_DAC_A_CTRL, 122 - data->cs4245_regs[CS4245_DAC_A_CTRL]); 123 - cs4245_write(chip, CS4245_DAC_B_CTRL, 124 - data->cs4245_regs[CS4245_DAC_B_CTRL]); 125 - cs4245_write(chip, CS4245_DAC_CTRL_2, 126 - CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC); 127 - cs4245_write(chip, CS4245_INT_MASK, 0); 128 - cs4245_write(chip, CS4245_POWER_CTRL, 0); 108 + for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) { 109 + ret = (op == CS4245_SAVE_TO_SHADOW ? 110 + cs4245_read_spi(chip, addr) : 111 + cs4245_write_spi(chip, addr)); 112 + if (ret < 0) 113 + return ret; 114 + } 115 + return 0; 129 116 } 130 117 131 118 static void cs4245_init(struct oxygen *chip) 132 119 { 133 120 struct dg *data = chip->model_data; 134 121 135 - data->cs4245_regs[CS4245_DAC_CTRL_1] = 122 + /* save the initial state: codec version, registers */ 123 + cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW); 124 + 125 + /* 126 + * Power up the CODEC internals, enable soft ramp & zero cross, work in 127 + * async. mode, enable aux output from DAC. Invert DAC output as in the 128 + * Windows driver. 129 + */ 130 + data->cs4245_shadow[CS4245_POWER_CTRL] = 0; 131 + data->cs4245_shadow[CS4245_SIGNAL_SEL] = 132 + CS4245_A_OUT_SEL_DAC | CS4245_ASYNCH; 133 + data->cs4245_shadow[CS4245_DAC_CTRL_1] = 136 134 CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST; 137 - data->cs4245_regs[CS4245_ADC_CTRL] = 135 + data->cs4245_shadow[CS4245_DAC_CTRL_2] = 136 + CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC; 137 + data->cs4245_shadow[CS4245_ADC_CTRL] = 138 138 CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST; 139 - data->cs4245_regs[CS4245_SIGNAL_SEL] = 140 - CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH; 141 - data->cs4245_regs[CS4245_PGA_B_CTRL] = 0; 142 - data->cs4245_regs[CS4245_PGA_A_CTRL] = 0; 143 - data->cs4245_regs[CS4245_ANALOG_IN] = 144 - CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4; 145 - data->cs4245_regs[CS4245_DAC_A_CTRL] = 0; 146 - data->cs4245_regs[CS4245_DAC_B_CTRL] = 0; 147 - cs4245_registers_init(chip); 139 + data->cs4245_shadow[CS4245_ANALOG_IN] = 140 + CS4245_PGA_SOFT | CS4245_PGA_ZERO; 141 + data->cs4245_shadow[CS4245_PGA_B_CTRL] = 0; 142 + data->cs4245_shadow[CS4245_PGA_A_CTRL] = 0; 143 + data->cs4245_shadow[CS4245_DAC_A_CTRL] = 8; 144 + data->cs4245_shadow[CS4245_DAC_B_CTRL] = 8; 145 + 146 + cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW); 148 147 snd_component_add(chip->card, "CS4245"); 149 148 } 150 149 151 - static void dg_output_enable(struct oxygen *chip) 152 - { 153 - msleep(2500); 154 - oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 155 - } 156 - 157 - static void dg_init(struct oxygen *chip) 150 + void dg_init(struct oxygen *chip) 158 151 { 159 152 struct dg *data = chip->model_data; 160 153 161 - data->output_sel = 0; 162 - data->input_sel = 3; 163 - data->hp_vol_att = 2 * 16; 154 + data->output_sel = PLAYBACK_DST_HP_FP; 155 + data->input_sel = CAPTURE_SRC_MIC; 164 156 165 157 cs4245_init(chip); 166 - 167 - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, 168 - GPIO_MAGIC | GPIO_HP_DETECT); 169 - oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, 170 - GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE); 171 - oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, 172 - GPIO_INPUT_ROUTE | GPIO_HP_REAR); 173 - dg_output_enable(chip); 158 + oxygen_write16(chip, OXYGEN_GPIO_CONTROL, 159 + GPIO_OUTPUT_ENABLE | GPIO_HP_REAR | GPIO_INPUT_ROUTE); 160 + /* anti-pop delay, wait some time before enabling the output */ 161 + msleep(2500); 162 + oxygen_write16(chip, OXYGEN_GPIO_DATA, 163 + GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE); 174 164 } 175 165 176 - static void dg_cleanup(struct oxygen *chip) 166 + void dg_cleanup(struct oxygen *chip) 177 167 { 178 168 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 179 169 } 180 170 181 - static void dg_suspend(struct oxygen *chip) 171 + void dg_suspend(struct oxygen *chip) 182 172 { 183 173 dg_cleanup(chip); 184 174 } 185 175 186 - static void dg_resume(struct oxygen *chip) 176 + void dg_resume(struct oxygen *chip) 187 177 { 188 - cs4245_registers_init(chip); 189 - dg_output_enable(chip); 178 + cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW); 179 + msleep(2500); 180 + oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 190 181 } 191 182 192 - static void set_cs4245_dac_params(struct oxygen *chip, 183 + void set_cs4245_dac_params(struct oxygen *chip, 193 184 struct snd_pcm_hw_params *params) 194 185 { 195 186 struct dg *data = chip->model_data; 196 - u8 value; 187 + unsigned char dac_ctrl; 188 + unsigned char mclk_freq; 197 189 198 - value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK; 199 - if (params_rate(params) <= 50000) 200 - value |= CS4245_DAC_FM_SINGLE; 201 - else if (params_rate(params) <= 100000) 202 - value |= CS4245_DAC_FM_DOUBLE; 203 - else 204 - value |= CS4245_DAC_FM_QUAD; 205 - cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value); 190 + dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK; 191 + mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK; 192 + if (params_rate(params) <= 50000) { 193 + dac_ctrl |= CS4245_DAC_FM_SINGLE; 194 + mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT; 195 + } else if (params_rate(params) <= 100000) { 196 + dac_ctrl |= CS4245_DAC_FM_DOUBLE; 197 + mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT; 198 + } else { 199 + dac_ctrl |= CS4245_DAC_FM_QUAD; 200 + mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT; 201 + } 202 + data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl; 203 + data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq; 204 + cs4245_write_spi(chip, CS4245_DAC_CTRL_1); 205 + cs4245_write_spi(chip, CS4245_MCLK_FREQ); 206 206 } 207 207 208 - static void set_cs4245_adc_params(struct oxygen *chip, 208 + void set_cs4245_adc_params(struct oxygen *chip, 209 209 struct snd_pcm_hw_params *params) 210 210 { 211 211 struct dg *data = chip->model_data; 212 - u8 value; 212 + unsigned char adc_ctrl; 213 + unsigned char mclk_freq; 213 214 214 - value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK; 215 - if (params_rate(params) <= 50000) 216 - value |= CS4245_ADC_FM_SINGLE; 217 - else if (params_rate(params) <= 100000) 218 - value |= CS4245_ADC_FM_DOUBLE; 219 - else 220 - value |= CS4245_ADC_FM_QUAD; 221 - cs4245_write_cached(chip, CS4245_ADC_CTRL, value); 215 + adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK; 216 + mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK; 217 + if (params_rate(params) <= 50000) { 218 + adc_ctrl |= CS4245_ADC_FM_SINGLE; 219 + mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT; 220 + } else if (params_rate(params) <= 100000) { 221 + adc_ctrl |= CS4245_ADC_FM_DOUBLE; 222 + mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT; 223 + } else { 224 + adc_ctrl |= CS4245_ADC_FM_QUAD; 225 + mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT; 226 + } 227 + data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl; 228 + data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq; 229 + cs4245_write_spi(chip, CS4245_ADC_CTRL); 230 + cs4245_write_spi(chip, CS4245_MCLK_FREQ); 222 231 } 223 232 224 - static inline unsigned int shift_bits(unsigned int value, 225 - unsigned int shift_from, 226 - unsigned int shift_to, 227 - unsigned int mask) 228 - { 229 - if (shift_from < shift_to) 230 - return (value << (shift_to - shift_from)) & mask; 231 - else 232 - return (value >> (shift_from - shift_to)) & mask; 233 - } 234 - 235 - static unsigned int adjust_dg_dac_routing(struct oxygen *chip, 233 + unsigned int adjust_dg_dac_routing(struct oxygen *chip, 236 234 unsigned int play_routing) 237 235 { 238 - return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) | 239 - shift_bits(play_routing, 240 - OXYGEN_PLAY_DAC2_SOURCE_SHIFT, 241 - OXYGEN_PLAY_DAC1_SOURCE_SHIFT, 242 - OXYGEN_PLAY_DAC1_SOURCE_MASK) | 243 - shift_bits(play_routing, 244 - OXYGEN_PLAY_DAC1_SOURCE_SHIFT, 245 - OXYGEN_PLAY_DAC2_SOURCE_SHIFT, 246 - OXYGEN_PLAY_DAC2_SOURCE_MASK) | 247 - shift_bits(play_routing, 248 - OXYGEN_PLAY_DAC0_SOURCE_SHIFT, 249 - OXYGEN_PLAY_DAC3_SOURCE_SHIFT, 250 - OXYGEN_PLAY_DAC3_SOURCE_MASK); 251 - } 252 - 253 - static int output_switch_info(struct snd_kcontrol *ctl, 254 - struct snd_ctl_elem_info *info) 255 - { 256 - static const char *const names[3] = { 257 - "Speakers", "Headphones", "FP Headphones" 258 - }; 259 - 260 - return snd_ctl_enum_info(info, 1, 3, names); 261 - } 262 - 263 - static int output_switch_get(struct snd_kcontrol *ctl, 264 - struct snd_ctl_elem_value *value) 265 - { 266 - struct oxygen *chip = ctl->private_data; 267 236 struct dg *data = chip->model_data; 237 + unsigned int routing = 0; 268 238 269 - mutex_lock(&chip->mutex); 270 - value->value.enumerated.item[0] = data->output_sel; 271 - mutex_unlock(&chip->mutex); 272 - return 0; 273 - } 274 - 275 - static int output_switch_put(struct snd_kcontrol *ctl, 276 - struct snd_ctl_elem_value *value) 277 - { 278 - struct oxygen *chip = ctl->private_data; 279 - struct dg *data = chip->model_data; 280 - u8 reg; 281 - int changed; 282 - 283 - if (value->value.enumerated.item[0] > 2) 284 - return -EINVAL; 285 - 286 - mutex_lock(&chip->mutex); 287 - changed = value->value.enumerated.item[0] != data->output_sel; 288 - if (changed) { 289 - data->output_sel = value->value.enumerated.item[0]; 290 - 291 - reg = data->cs4245_regs[CS4245_SIGNAL_SEL] & 292 - ~CS4245_A_OUT_SEL_MASK; 293 - reg |= data->output_sel == 2 ? 294 - CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ; 295 - cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg); 296 - 297 - cs4245_write_cached(chip, CS4245_DAC_A_CTRL, 298 - data->output_sel ? data->hp_vol_att : 0); 299 - cs4245_write_cached(chip, CS4245_DAC_B_CTRL, 300 - data->output_sel ? data->hp_vol_att : 0); 301 - 302 - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 303 - data->output_sel == 1 ? GPIO_HP_REAR : 0, 304 - GPIO_HP_REAR); 239 + switch (data->output_sel) { 240 + case PLAYBACK_DST_HP: 241 + case PLAYBACK_DST_HP_FP: 242 + oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING, 243 + OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 | 244 + OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK); 245 + break; 246 + case PLAYBACK_DST_MULTICH: 247 + routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | 248 + (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 249 + (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | 250 + (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); 251 + oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING, 252 + OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK); 253 + break; 305 254 } 306 - mutex_unlock(&chip->mutex); 307 - return changed; 255 + return routing; 308 256 } 309 257 310 - static int hp_volume_offset_info(struct snd_kcontrol *ctl, 311 - struct snd_ctl_elem_info *info) 312 - { 313 - static const char *const names[3] = { 314 - "< 64 ohms", "64-150 ohms", "150-300 ohms" 315 - }; 316 - 317 - return snd_ctl_enum_info(info, 1, 3, names); 318 - } 319 - 320 - static int hp_volume_offset_get(struct snd_kcontrol *ctl, 321 - struct snd_ctl_elem_value *value) 322 - { 323 - struct oxygen *chip = ctl->private_data; 324 - struct dg *data = chip->model_data; 325 - 326 - mutex_lock(&chip->mutex); 327 - if (data->hp_vol_att > 2 * 7) 328 - value->value.enumerated.item[0] = 0; 329 - else if (data->hp_vol_att > 0) 330 - value->value.enumerated.item[0] = 1; 331 - else 332 - value->value.enumerated.item[0] = 2; 333 - mutex_unlock(&chip->mutex); 334 - return 0; 335 - } 336 - 337 - static int hp_volume_offset_put(struct snd_kcontrol *ctl, 338 - struct snd_ctl_elem_value *value) 339 - { 340 - static const s8 atts[3] = { 2 * 16, 2 * 7, 0 }; 341 - struct oxygen *chip = ctl->private_data; 342 - struct dg *data = chip->model_data; 343 - s8 att; 344 - int changed; 345 - 346 - if (value->value.enumerated.item[0] > 2) 347 - return -EINVAL; 348 - att = atts[value->value.enumerated.item[0]]; 349 - mutex_lock(&chip->mutex); 350 - changed = att != data->hp_vol_att; 351 - if (changed) { 352 - data->hp_vol_att = att; 353 - if (data->output_sel) { 354 - cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att); 355 - cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att); 356 - } 357 - } 358 - mutex_unlock(&chip->mutex); 359 - return changed; 360 - } 361 - 362 - static int input_vol_info(struct snd_kcontrol *ctl, 363 - struct snd_ctl_elem_info *info) 364 - { 365 - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 366 - info->count = 2; 367 - info->value.integer.min = 2 * -12; 368 - info->value.integer.max = 2 * 12; 369 - return 0; 370 - } 371 - 372 - static int input_vol_get(struct snd_kcontrol *ctl, 373 - struct snd_ctl_elem_value *value) 374 - { 375 - struct oxygen *chip = ctl->private_data; 376 - struct dg *data = chip->model_data; 377 - unsigned int idx = ctl->private_value; 378 - 379 - mutex_lock(&chip->mutex); 380 - value->value.integer.value[0] = data->input_vol[idx][0]; 381 - value->value.integer.value[1] = data->input_vol[idx][1]; 382 - mutex_unlock(&chip->mutex); 383 - return 0; 384 - } 385 - 386 - static int input_vol_put(struct snd_kcontrol *ctl, 387 - struct snd_ctl_elem_value *value) 388 - { 389 - struct oxygen *chip = ctl->private_data; 390 - struct dg *data = chip->model_data; 391 - unsigned int idx = ctl->private_value; 392 - int changed = 0; 393 - 394 - if (value->value.integer.value[0] < 2 * -12 || 395 - value->value.integer.value[0] > 2 * 12 || 396 - value->value.integer.value[1] < 2 * -12 || 397 - value->value.integer.value[1] > 2 * 12) 398 - return -EINVAL; 399 - mutex_lock(&chip->mutex); 400 - changed = data->input_vol[idx][0] != value->value.integer.value[0] || 401 - data->input_vol[idx][1] != value->value.integer.value[1]; 402 - if (changed) { 403 - data->input_vol[idx][0] = value->value.integer.value[0]; 404 - data->input_vol[idx][1] = value->value.integer.value[1]; 405 - if (idx == data->input_sel) { 406 - cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 407 - data->input_vol[idx][0]); 408 - cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 409 - data->input_vol[idx][1]); 410 - } 411 - } 412 - mutex_unlock(&chip->mutex); 413 - return changed; 414 - } 415 - 416 - static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); 417 - 418 - static int input_sel_info(struct snd_kcontrol *ctl, 419 - struct snd_ctl_elem_info *info) 420 - { 421 - static const char *const names[4] = { 422 - "Mic", "Aux", "Front Mic", "Line" 423 - }; 424 - 425 - return snd_ctl_enum_info(info, 1, 4, names); 426 - } 427 - 428 - static int input_sel_get(struct snd_kcontrol *ctl, 429 - struct snd_ctl_elem_value *value) 430 - { 431 - struct oxygen *chip = ctl->private_data; 432 - struct dg *data = chip->model_data; 433 - 434 - mutex_lock(&chip->mutex); 435 - value->value.enumerated.item[0] = data->input_sel; 436 - mutex_unlock(&chip->mutex); 437 - return 0; 438 - } 439 - 440 - static int input_sel_put(struct snd_kcontrol *ctl, 441 - struct snd_ctl_elem_value *value) 442 - { 443 - static const u8 sel_values[4] = { 444 - CS4245_SEL_MIC, 445 - CS4245_SEL_INPUT_1, 446 - CS4245_SEL_INPUT_2, 447 - CS4245_SEL_INPUT_4 448 - }; 449 - struct oxygen *chip = ctl->private_data; 450 - struct dg *data = chip->model_data; 451 - int changed; 452 - 453 - if (value->value.enumerated.item[0] > 3) 454 - return -EINVAL; 455 - 456 - mutex_lock(&chip->mutex); 457 - changed = value->value.enumerated.item[0] != data->input_sel; 458 - if (changed) { 459 - data->input_sel = value->value.enumerated.item[0]; 460 - 461 - cs4245_write(chip, CS4245_ANALOG_IN, 462 - (data->cs4245_regs[CS4245_ANALOG_IN] & 463 - ~CS4245_SEL_MASK) | 464 - sel_values[data->input_sel]); 465 - 466 - cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 467 - data->input_vol[data->input_sel][0]); 468 - cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 469 - data->input_vol[data->input_sel][1]); 470 - 471 - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 472 - data->input_sel ? 0 : GPIO_INPUT_ROUTE, 473 - GPIO_INPUT_ROUTE); 474 - } 475 - mutex_unlock(&chip->mutex); 476 - return changed; 477 - } 478 - 479 - static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 480 - { 481 - static const char *const names[2] = { "Active", "Frozen" }; 482 - 483 - return snd_ctl_enum_info(info, 1, 2, names); 484 - } 485 - 486 - static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 487 - { 488 - struct oxygen *chip = ctl->private_data; 489 - struct dg *data = chip->model_data; 490 - 491 - value->value.enumerated.item[0] = 492 - !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); 493 - return 0; 494 - } 495 - 496 - static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 497 - { 498 - struct oxygen *chip = ctl->private_data; 499 - struct dg *data = chip->model_data; 500 - u8 reg; 501 - int changed; 502 - 503 - mutex_lock(&chip->mutex); 504 - reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; 505 - if (value->value.enumerated.item[0]) 506 - reg |= CS4245_HPF_FREEZE; 507 - changed = reg != data->cs4245_regs[CS4245_ADC_CTRL]; 508 - if (changed) 509 - cs4245_write(chip, CS4245_ADC_CTRL, reg); 510 - mutex_unlock(&chip->mutex); 511 - return changed; 512 - } 513 - 514 - #define INPUT_VOLUME(xname, index) { \ 515 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 516 - .name = xname, \ 517 - .info = input_vol_info, \ 518 - .get = input_vol_get, \ 519 - .put = input_vol_put, \ 520 - .tlv = { .p = cs4245_pga_db_scale }, \ 521 - .private_value = index, \ 522 - } 523 - static const struct snd_kcontrol_new dg_controls[] = { 524 - { 525 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 526 - .name = "Analog Output Playback Enum", 527 - .info = output_switch_info, 528 - .get = output_switch_get, 529 - .put = output_switch_put, 530 - }, 531 - { 532 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 533 - .name = "Headphones Impedance Playback Enum", 534 - .info = hp_volume_offset_info, 535 - .get = hp_volume_offset_get, 536 - .put = hp_volume_offset_put, 537 - }, 538 - INPUT_VOLUME("Mic Capture Volume", 0), 539 - INPUT_VOLUME("Aux Capture Volume", 1), 540 - INPUT_VOLUME("Front Mic Capture Volume", 2), 541 - INPUT_VOLUME("Line Capture Volume", 3), 542 - { 543 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 544 - .name = "Capture Source", 545 - .info = input_sel_info, 546 - .get = input_sel_get, 547 - .put = input_sel_put, 548 - }, 549 - { 550 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 551 - .name = "ADC High-pass Filter Capture Enum", 552 - .info = hpf_info, 553 - .get = hpf_get, 554 - .put = hpf_put, 555 - }, 556 - }; 557 - 558 - static int dg_control_filter(struct snd_kcontrol_new *template) 559 - { 560 - if (!strncmp(template->name, "Master Playback ", 16)) 561 - return 1; 562 - return 0; 563 - } 564 - 565 - static int dg_mixer_init(struct oxygen *chip) 566 - { 567 - unsigned int i; 568 - int err; 569 - 570 - for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { 571 - err = snd_ctl_add(chip->card, 572 - snd_ctl_new1(&dg_controls[i], chip)); 573 - if (err < 0) 574 - return err; 575 - } 576 - return 0; 577 - } 578 - 579 - static void dump_cs4245_registers(struct oxygen *chip, 258 + void dump_cs4245_registers(struct oxygen *chip, 580 259 struct snd_info_buffer *buffer) 581 260 { 582 261 struct dg *data = chip->model_data; 583 - unsigned int i; 262 + unsigned int addr; 584 263 585 264 snd_iprintf(buffer, "\nCS4245:"); 586 - for (i = 1; i <= 0x10; ++i) 587 - snd_iprintf(buffer, " %02x", data->cs4245_regs[i]); 265 + cs4245_read_spi(chip, CS4245_INT_STATUS); 266 + for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) 267 + snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]); 588 268 snd_iprintf(buffer, "\n"); 589 269 } 590 - 591 - struct oxygen_model model_xonar_dg = { 592 - .longname = "C-Media Oxygen HD Audio", 593 - .chip = "CMI8786", 594 - .init = dg_init, 595 - .control_filter = dg_control_filter, 596 - .mixer_init = dg_mixer_init, 597 - .cleanup = dg_cleanup, 598 - .suspend = dg_suspend, 599 - .resume = dg_resume, 600 - .set_dac_params = set_cs4245_dac_params, 601 - .set_adc_params = set_cs4245_adc_params, 602 - .adjust_dac_routing = adjust_dg_dac_routing, 603 - .dump_registers = dump_cs4245_registers, 604 - .model_data_size = sizeof(struct dg), 605 - .device_config = PLAYBACK_0_TO_I2S | 606 - PLAYBACK_1_TO_SPDIF | 607 - CAPTURE_0_FROM_I2S_2 | 608 - CAPTURE_1_FROM_SPDIF, 609 - .dac_channels_pcm = 6, 610 - .dac_channels_mixer = 0, 611 - .function_flags = OXYGEN_FUNCTION_SPI, 612 - .dac_mclks = OXYGEN_MCLKS(256, 128, 128), 613 - .adc_mclks = OXYGEN_MCLKS(256, 128, 128), 614 - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 615 - .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 616 - };
+48
sound/pci/oxygen/xonar_dg.h
··· 3 3 4 4 #include "oxygen.h" 5 5 6 + #define GPIO_MAGIC 0x0008 7 + #define GPIO_HP_DETECT 0x0010 8 + #define GPIO_INPUT_ROUTE 0x0060 9 + #define GPIO_HP_REAR 0x0080 10 + #define GPIO_OUTPUT_ENABLE 0x0100 11 + 12 + #define CAPTURE_SRC_MIC 0 13 + #define CAPTURE_SRC_FP_MIC 1 14 + #define CAPTURE_SRC_LINE 2 15 + #define CAPTURE_SRC_AUX 3 16 + 17 + #define PLAYBACK_DST_HP 0 18 + #define PLAYBACK_DST_HP_FP 1 19 + #define PLAYBACK_DST_MULTICH 2 20 + 21 + enum cs4245_shadow_operation { 22 + CS4245_SAVE_TO_SHADOW, 23 + CS4245_LOAD_FROM_SHADOW 24 + }; 25 + 26 + struct dg { 27 + /* shadow copy of the CS4245 register space */ 28 + unsigned char cs4245_shadow[17]; 29 + /* output select: headphone/speakers */ 30 + unsigned char output_sel; 31 + /* volumes for all capture sources */ 32 + char input_vol[4][2]; 33 + /* input select: mic/fp mic/line/aux */ 34 + unsigned char input_sel; 35 + }; 36 + 37 + /* Xonar DG control routines */ 38 + int cs4245_write_spi(struct oxygen *chip, u8 reg); 39 + int cs4245_read_spi(struct oxygen *chip, u8 reg); 40 + int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op); 41 + void dg_init(struct oxygen *chip); 42 + void set_cs4245_dac_params(struct oxygen *chip, 43 + struct snd_pcm_hw_params *params); 44 + void set_cs4245_adc_params(struct oxygen *chip, 45 + struct snd_pcm_hw_params *params); 46 + unsigned int adjust_dg_dac_routing(struct oxygen *chip, 47 + unsigned int play_routing); 48 + void dump_cs4245_registers(struct oxygen *chip, 49 + struct snd_info_buffer *buffer); 50 + void dg_suspend(struct oxygen *chip); 51 + void dg_resume(struct oxygen *chip); 52 + void dg_cleanup(struct oxygen *chip); 53 + 6 54 extern struct oxygen_model model_xonar_dg; 7 55 8 56 #endif
+477
sound/pci/oxygen/xonar_dg_mixer.c
··· 1 + /* 2 + * Mixer controls for the Xonar DG/DGX 3 + * 4 + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 5 + * Copyright (c) Roman Volkov <v1ron@mail.ru> 6 + * 7 + * This driver is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License, version 2. 9 + * 10 + * This driver is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this driver; if not, see <http://www.gnu.org/licenses/>. 17 + */ 18 + 19 + #include <linux/pci.h> 20 + #include <linux/delay.h> 21 + #include <sound/control.h> 22 + #include <sound/core.h> 23 + #include <sound/info.h> 24 + #include <sound/pcm.h> 25 + #include <sound/tlv.h> 26 + #include "oxygen.h" 27 + #include "xonar_dg.h" 28 + #include "cs4245.h" 29 + 30 + /* analog output select */ 31 + 32 + static int output_select_apply(struct oxygen *chip) 33 + { 34 + struct dg *data = chip->model_data; 35 + 36 + data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK; 37 + if (data->output_sel == PLAYBACK_DST_HP) { 38 + /* mute FP (aux output) amplifier, switch rear jack to CS4245 */ 39 + oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 40 + } else if (data->output_sel == PLAYBACK_DST_HP_FP) { 41 + /* 42 + * Unmute FP amplifier, switch rear jack to CS4361; 43 + * I2S channels 2,3,4 should be inactive. 44 + */ 45 + oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 46 + data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC; 47 + } else { 48 + /* 49 + * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp., 50 + * and change playback routing. 51 + */ 52 + oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 53 + } 54 + return cs4245_write_spi(chip, CS4245_SIGNAL_SEL); 55 + } 56 + 57 + static int output_select_info(struct snd_kcontrol *ctl, 58 + struct snd_ctl_elem_info *info) 59 + { 60 + static const char *const names[3] = { 61 + "Stereo Headphones", 62 + "Stereo Headphones FP", 63 + "Multichannel", 64 + }; 65 + 66 + return snd_ctl_enum_info(info, 1, 3, names); 67 + } 68 + 69 + static int output_select_get(struct snd_kcontrol *ctl, 70 + struct snd_ctl_elem_value *value) 71 + { 72 + struct oxygen *chip = ctl->private_data; 73 + struct dg *data = chip->model_data; 74 + 75 + mutex_lock(&chip->mutex); 76 + value->value.enumerated.item[0] = data->output_sel; 77 + mutex_unlock(&chip->mutex); 78 + return 0; 79 + } 80 + 81 + static int output_select_put(struct snd_kcontrol *ctl, 82 + struct snd_ctl_elem_value *value) 83 + { 84 + struct oxygen *chip = ctl->private_data; 85 + struct dg *data = chip->model_data; 86 + unsigned int new = value->value.enumerated.item[0]; 87 + int changed = 0; 88 + int ret; 89 + 90 + mutex_lock(&chip->mutex); 91 + if (data->output_sel != new) { 92 + data->output_sel = new; 93 + ret = output_select_apply(chip); 94 + changed = ret >= 0 ? 1 : ret; 95 + oxygen_update_dac_routing(chip); 96 + } 97 + mutex_unlock(&chip->mutex); 98 + 99 + return changed; 100 + } 101 + 102 + /* CS4245 Headphone Channels A&B Volume Control */ 103 + 104 + static int hp_stereo_volume_info(struct snd_kcontrol *ctl, 105 + struct snd_ctl_elem_info *info) 106 + { 107 + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 108 + info->count = 2; 109 + info->value.integer.min = 0; 110 + info->value.integer.max = 255; 111 + return 0; 112 + } 113 + 114 + static int hp_stereo_volume_get(struct snd_kcontrol *ctl, 115 + struct snd_ctl_elem_value *val) 116 + { 117 + struct oxygen *chip = ctl->private_data; 118 + struct dg *data = chip->model_data; 119 + unsigned int tmp; 120 + 121 + mutex_lock(&chip->mutex); 122 + tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255; 123 + val->value.integer.value[0] = tmp; 124 + tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255; 125 + val->value.integer.value[1] = tmp; 126 + mutex_unlock(&chip->mutex); 127 + return 0; 128 + } 129 + 130 + static int hp_stereo_volume_put(struct snd_kcontrol *ctl, 131 + struct snd_ctl_elem_value *val) 132 + { 133 + struct oxygen *chip = ctl->private_data; 134 + struct dg *data = chip->model_data; 135 + int ret; 136 + int changed = 0; 137 + long new1 = val->value.integer.value[0]; 138 + long new2 = val->value.integer.value[1]; 139 + 140 + if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0)) 141 + return -EINVAL; 142 + 143 + mutex_lock(&chip->mutex); 144 + if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) || 145 + (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) { 146 + data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1; 147 + data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~new2; 148 + ret = cs4245_write_spi(chip, CS4245_DAC_A_CTRL); 149 + if (ret >= 0) 150 + ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL); 151 + changed = ret >= 0 ? 1 : ret; 152 + } 153 + mutex_unlock(&chip->mutex); 154 + 155 + return changed; 156 + } 157 + 158 + /* Headphone Mute */ 159 + 160 + static int hp_mute_get(struct snd_kcontrol *ctl, 161 + struct snd_ctl_elem_value *val) 162 + { 163 + struct oxygen *chip = ctl->private_data; 164 + struct dg *data = chip->model_data; 165 + 166 + mutex_lock(&chip->mutex); 167 + val->value.integer.value[0] = 168 + !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC); 169 + mutex_unlock(&chip->mutex); 170 + return 0; 171 + } 172 + 173 + static int hp_mute_put(struct snd_kcontrol *ctl, 174 + struct snd_ctl_elem_value *val) 175 + { 176 + struct oxygen *chip = ctl->private_data; 177 + struct dg *data = chip->model_data; 178 + int ret; 179 + int changed; 180 + 181 + if (val->value.integer.value[0] > 1) 182 + return -EINVAL; 183 + mutex_lock(&chip->mutex); 184 + data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC; 185 + data->cs4245_shadow[CS4245_DAC_CTRL_1] |= 186 + (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC; 187 + ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1); 188 + changed = ret >= 0 ? 1 : ret; 189 + mutex_unlock(&chip->mutex); 190 + return changed; 191 + } 192 + 193 + /* capture volume for all sources */ 194 + 195 + static int input_volume_apply(struct oxygen *chip, char left, char right) 196 + { 197 + struct dg *data = chip->model_data; 198 + int ret; 199 + 200 + data->cs4245_shadow[CS4245_PGA_A_CTRL] = left; 201 + data->cs4245_shadow[CS4245_PGA_B_CTRL] = right; 202 + ret = cs4245_write_spi(chip, CS4245_PGA_A_CTRL); 203 + if (ret < 0) 204 + return ret; 205 + return cs4245_write_spi(chip, CS4245_PGA_B_CTRL); 206 + } 207 + 208 + static int input_vol_info(struct snd_kcontrol *ctl, 209 + struct snd_ctl_elem_info *info) 210 + { 211 + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 212 + info->count = 2; 213 + info->value.integer.min = 2 * -12; 214 + info->value.integer.max = 2 * 12; 215 + return 0; 216 + } 217 + 218 + static int input_vol_get(struct snd_kcontrol *ctl, 219 + struct snd_ctl_elem_value *value) 220 + { 221 + struct oxygen *chip = ctl->private_data; 222 + struct dg *data = chip->model_data; 223 + unsigned int idx = ctl->private_value; 224 + 225 + mutex_lock(&chip->mutex); 226 + value->value.integer.value[0] = data->input_vol[idx][0]; 227 + value->value.integer.value[1] = data->input_vol[idx][1]; 228 + mutex_unlock(&chip->mutex); 229 + return 0; 230 + } 231 + 232 + static int input_vol_put(struct snd_kcontrol *ctl, 233 + struct snd_ctl_elem_value *value) 234 + { 235 + struct oxygen *chip = ctl->private_data; 236 + struct dg *data = chip->model_data; 237 + unsigned int idx = ctl->private_value; 238 + int changed = 0; 239 + int ret = 0; 240 + 241 + if (value->value.integer.value[0] < 2 * -12 || 242 + value->value.integer.value[0] > 2 * 12 || 243 + value->value.integer.value[1] < 2 * -12 || 244 + value->value.integer.value[1] > 2 * 12) 245 + return -EINVAL; 246 + mutex_lock(&chip->mutex); 247 + changed = data->input_vol[idx][0] != value->value.integer.value[0] || 248 + data->input_vol[idx][1] != value->value.integer.value[1]; 249 + if (changed) { 250 + data->input_vol[idx][0] = value->value.integer.value[0]; 251 + data->input_vol[idx][1] = value->value.integer.value[1]; 252 + if (idx == data->input_sel) { 253 + ret = input_volume_apply(chip, 254 + data->input_vol[idx][0], 255 + data->input_vol[idx][1]); 256 + } 257 + changed = ret >= 0 ? 1 : ret; 258 + } 259 + mutex_unlock(&chip->mutex); 260 + return changed; 261 + } 262 + 263 + /* Capture Source */ 264 + 265 + static int input_source_apply(struct oxygen *chip) 266 + { 267 + struct dg *data = chip->model_data; 268 + 269 + data->cs4245_shadow[CS4245_ANALOG_IN] &= ~CS4245_SEL_MASK; 270 + if (data->input_sel == CAPTURE_SRC_FP_MIC) 271 + data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_2; 272 + else if (data->input_sel == CAPTURE_SRC_LINE) 273 + data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_4; 274 + else if (data->input_sel != CAPTURE_SRC_MIC) 275 + data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_1; 276 + return cs4245_write_spi(chip, CS4245_ANALOG_IN); 277 + } 278 + 279 + static int input_sel_info(struct snd_kcontrol *ctl, 280 + struct snd_ctl_elem_info *info) 281 + { 282 + static const char *const names[4] = { 283 + "Mic", "Front Mic", "Line", "Aux" 284 + }; 285 + 286 + return snd_ctl_enum_info(info, 1, 4, names); 287 + } 288 + 289 + static int input_sel_get(struct snd_kcontrol *ctl, 290 + struct snd_ctl_elem_value *value) 291 + { 292 + struct oxygen *chip = ctl->private_data; 293 + struct dg *data = chip->model_data; 294 + 295 + mutex_lock(&chip->mutex); 296 + value->value.enumerated.item[0] = data->input_sel; 297 + mutex_unlock(&chip->mutex); 298 + return 0; 299 + } 300 + 301 + static int input_sel_put(struct snd_kcontrol *ctl, 302 + struct snd_ctl_elem_value *value) 303 + { 304 + struct oxygen *chip = ctl->private_data; 305 + struct dg *data = chip->model_data; 306 + int changed; 307 + int ret; 308 + 309 + if (value->value.enumerated.item[0] > 3) 310 + return -EINVAL; 311 + 312 + mutex_lock(&chip->mutex); 313 + changed = value->value.enumerated.item[0] != data->input_sel; 314 + if (changed) { 315 + data->input_sel = value->value.enumerated.item[0]; 316 + 317 + ret = input_source_apply(chip); 318 + if (ret >= 0) 319 + ret = input_volume_apply(chip, 320 + data->input_vol[data->input_sel][0], 321 + data->input_vol[data->input_sel][1]); 322 + changed = ret >= 0 ? 1 : ret; 323 + } 324 + mutex_unlock(&chip->mutex); 325 + return changed; 326 + } 327 + 328 + /* ADC high-pass filter */ 329 + 330 + static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 331 + { 332 + static const char *const names[2] = { "Active", "Frozen" }; 333 + 334 + return snd_ctl_enum_info(info, 1, 2, names); 335 + } 336 + 337 + static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 338 + { 339 + struct oxygen *chip = ctl->private_data; 340 + struct dg *data = chip->model_data; 341 + 342 + value->value.enumerated.item[0] = 343 + !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); 344 + return 0; 345 + } 346 + 347 + static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 348 + { 349 + struct oxygen *chip = ctl->private_data; 350 + struct dg *data = chip->model_data; 351 + u8 reg; 352 + int changed; 353 + 354 + mutex_lock(&chip->mutex); 355 + reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; 356 + if (value->value.enumerated.item[0]) 357 + reg |= CS4245_HPF_FREEZE; 358 + changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL]; 359 + if (changed) { 360 + data->cs4245_shadow[CS4245_ADC_CTRL] = reg; 361 + cs4245_write_spi(chip, CS4245_ADC_CTRL); 362 + } 363 + mutex_unlock(&chip->mutex); 364 + return changed; 365 + } 366 + 367 + #define INPUT_VOLUME(xname, index) { \ 368 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 369 + .name = xname, \ 370 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 371 + SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 372 + .info = input_vol_info, \ 373 + .get = input_vol_get, \ 374 + .put = input_vol_put, \ 375 + .tlv = { .p = pga_db_scale }, \ 376 + .private_value = index, \ 377 + } 378 + static const DECLARE_TLV_DB_MINMAX(hp_db_scale, -12550, 0); 379 + static const DECLARE_TLV_DB_MINMAX(pga_db_scale, -1200, 1200); 380 + static const struct snd_kcontrol_new dg_controls[] = { 381 + { 382 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 383 + .name = "Analog Output Playback Enum", 384 + .info = output_select_info, 385 + .get = output_select_get, 386 + .put = output_select_put, 387 + }, 388 + { 389 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 390 + .name = "Headphone Playback Volume", 391 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 392 + SNDRV_CTL_ELEM_ACCESS_TLV_READ, 393 + .info = hp_stereo_volume_info, 394 + .get = hp_stereo_volume_get, 395 + .put = hp_stereo_volume_put, 396 + .tlv = { .p = hp_db_scale, }, 397 + }, 398 + { 399 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 400 + .name = "Headphone Playback Switch", 401 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 402 + .info = snd_ctl_boolean_mono_info, 403 + .get = hp_mute_get, 404 + .put = hp_mute_put, 405 + }, 406 + INPUT_VOLUME("Mic Capture Volume", CAPTURE_SRC_MIC), 407 + INPUT_VOLUME("Front Mic Capture Volume", CAPTURE_SRC_FP_MIC), 408 + INPUT_VOLUME("Line Capture Volume", CAPTURE_SRC_LINE), 409 + INPUT_VOLUME("Aux Capture Volume", CAPTURE_SRC_AUX), 410 + { 411 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 412 + .name = "Capture Source", 413 + .info = input_sel_info, 414 + .get = input_sel_get, 415 + .put = input_sel_put, 416 + }, 417 + { 418 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 419 + .name = "ADC High-pass Filter Capture Enum", 420 + .info = hpf_info, 421 + .get = hpf_get, 422 + .put = hpf_put, 423 + }, 424 + }; 425 + 426 + static int dg_control_filter(struct snd_kcontrol_new *template) 427 + { 428 + if (!strncmp(template->name, "Master Playback ", 16)) 429 + return 1; 430 + return 0; 431 + } 432 + 433 + static int dg_mixer_init(struct oxygen *chip) 434 + { 435 + unsigned int i; 436 + int err; 437 + 438 + output_select_apply(chip); 439 + input_source_apply(chip); 440 + oxygen_update_dac_routing(chip); 441 + 442 + for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { 443 + err = snd_ctl_add(chip->card, 444 + snd_ctl_new1(&dg_controls[i], chip)); 445 + if (err < 0) 446 + return err; 447 + } 448 + 449 + return 0; 450 + } 451 + 452 + struct oxygen_model model_xonar_dg = { 453 + .longname = "C-Media Oxygen HD Audio", 454 + .chip = "CMI8786", 455 + .init = dg_init, 456 + .control_filter = dg_control_filter, 457 + .mixer_init = dg_mixer_init, 458 + .cleanup = dg_cleanup, 459 + .suspend = dg_suspend, 460 + .resume = dg_resume, 461 + .set_dac_params = set_cs4245_dac_params, 462 + .set_adc_params = set_cs4245_adc_params, 463 + .adjust_dac_routing = adjust_dg_dac_routing, 464 + .dump_registers = dump_cs4245_registers, 465 + .model_data_size = sizeof(struct dg), 466 + .device_config = PLAYBACK_0_TO_I2S | 467 + PLAYBACK_1_TO_SPDIF | 468 + CAPTURE_0_FROM_I2S_1 | 469 + CAPTURE_1_FROM_SPDIF, 470 + .dac_channels_pcm = 6, 471 + .dac_channels_mixer = 0, 472 + .function_flags = OXYGEN_FUNCTION_SPI, 473 + .dac_mclks = OXYGEN_MCLKS(256, 128, 128), 474 + .adc_mclks = OXYGEN_MCLKS(256, 128, 128), 475 + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 476 + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 477 + };