1 // SPDX-License-Identifier: GPL-2.0-only 1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 2 /* 3 * card driver for the Xonar DG/DGX 3 * card driver for the Xonar DG/DGX 4 * 4 * 5 * Copyright (c) Clemens Ladisch <clemens@ladi 5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 6 * Copyright (c) Roman Volkov <v1ron@mail.ru> 6 * Copyright (c) Roman Volkov <v1ron@mail.ru> 7 */ 7 */ 8 8 9 /* 9 /* 10 * Xonar DG/DGX 10 * Xonar DG/DGX 11 * ------------ 11 * ------------ 12 * 12 * 13 * CS4245 and CS4361 both will mute all output 13 * CS4245 and CS4361 both will mute all outputs if any clock ratio 14 * is invalid. 14 * is invalid. 15 * 15 * 16 * CMI8788: 16 * CMI8788: 17 * 17 * 18 * SPI 0 -> CS4245 18 * SPI 0 -> CS4245 19 * 19 * 20 * Playback: 20 * Playback: 21 * I²S 1 -> CS4245 21 * I²S 1 -> CS4245 22 * I²S 2 -> CS4361 (center/LFE) 22 * I²S 2 -> CS4361 (center/LFE) 23 * I²S 3 -> CS4361 (surround) 23 * I²S 3 -> CS4361 (surround) 24 * I²S 4 -> CS4361 (front) 24 * I²S 4 -> CS4361 (front) 25 * Capture: 25 * Capture: 26 * I²S ADC 1 <- CS4245 26 * I²S ADC 1 <- CS4245 27 * 27 * 28 * GPIO 3 <- ? 28 * GPIO 3 <- ? 29 * GPIO 4 <- headphone detect 29 * GPIO 4 <- headphone detect 30 * GPIO 5 -> enable ADC analog circuit for t 30 * GPIO 5 -> enable ADC analog circuit for the left channel 31 * GPIO 6 -> enable ADC analog circuit for t 31 * GPIO 6 -> enable ADC analog circuit for the right channel 32 * GPIO 7 -> switch green rear output jack b 32 * GPIO 7 -> switch green rear output jack between CS4245 and the first 33 * channel of CS4361 (mechanical r 33 * channel of CS4361 (mechanical relay) 34 * GPIO 8 -> enable output to speakers 34 * GPIO 8 -> enable output to speakers 35 * 35 * 36 * CS4245: 36 * CS4245: 37 * 37 * 38 * input 0 <- mic 38 * input 0 <- mic 39 * input 1 <- aux 39 * input 1 <- aux 40 * input 2 <- front mic 40 * input 2 <- front mic 41 * input 4 <- line 41 * input 4 <- line 42 * DAC out -> headphones 42 * DAC out -> headphones 43 * aux out -> front panel headphones 43 * aux out -> front panel headphones 44 */ 44 */ 45 45 46 #include <linux/pci.h> 46 #include <linux/pci.h> 47 #include <linux/delay.h> 47 #include <linux/delay.h> 48 #include <sound/control.h> 48 #include <sound/control.h> 49 #include <sound/core.h> 49 #include <sound/core.h> 50 #include <sound/info.h> 50 #include <sound/info.h> 51 #include <sound/pcm.h> 51 #include <sound/pcm.h> 52 #include <sound/tlv.h> 52 #include <sound/tlv.h> 53 #include "oxygen.h" 53 #include "oxygen.h" 54 #include "xonar_dg.h" 54 #include "xonar_dg.h" 55 #include "cs4245.h" 55 #include "cs4245.h" 56 56 57 int cs4245_write_spi(struct oxygen *chip, u8 r 57 int cs4245_write_spi(struct oxygen *chip, u8 reg) 58 { 58 { 59 struct dg *data = chip->model_data; 59 struct dg *data = chip->model_data; 60 unsigned int packet; 60 unsigned int packet; 61 61 62 packet = reg << 8; 62 packet = reg << 8; 63 packet |= (CS4245_SPI_ADDRESS | CS4245 63 packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16; 64 packet |= data->cs4245_shadow[reg]; 64 packet |= data->cs4245_shadow[reg]; 65 65 66 return oxygen_write_spi(chip, OXYGEN_S 66 return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | 67 OXYGEN_SPI_DAT 67 OXYGEN_SPI_DATA_LENGTH_3 | 68 OXYGEN_SPI_CLO 68 OXYGEN_SPI_CLOCK_1280 | 69 (0 << OXYGEN_S 69 (0 << OXYGEN_SPI_CODEC_SHIFT) | 70 OXYGEN_SPI_CEN 70 OXYGEN_SPI_CEN_LATCH_CLOCK_HI, 71 packet); 71 packet); 72 } 72 } 73 73 74 int cs4245_read_spi(struct oxygen *chip, u8 ad 74 int cs4245_read_spi(struct oxygen *chip, u8 addr) 75 { 75 { 76 struct dg *data = chip->model_data; 76 struct dg *data = chip->model_data; 77 int ret; 77 int ret; 78 78 79 ret = oxygen_write_spi(chip, OXYGEN_SP 79 ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | 80 OXYGEN_SPI_DATA_LENGTH_2 | 80 OXYGEN_SPI_DATA_LENGTH_2 | 81 OXYGEN_SPI_CEN_LATCH_CLOCK_HI 81 OXYGEN_SPI_CEN_LATCH_CLOCK_HI | 82 OXYGEN_SPI_CLOCK_1280 | (0 << 82 OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT), 83 ((CS4245_SPI_ADDRESS | CS4245_ 83 ((CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 8) | addr); 84 if (ret < 0) 84 if (ret < 0) 85 return ret; 85 return ret; 86 86 87 ret = oxygen_write_spi(chip, OXYGEN_SP 87 ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | 88 OXYGEN_SPI_DATA_LENGTH_2 | 88 OXYGEN_SPI_DATA_LENGTH_2 | 89 OXYGEN_SPI_CEN_LATCH_CLOCK_HI 89 OXYGEN_SPI_CEN_LATCH_CLOCK_HI | 90 OXYGEN_SPI_CLOCK_1280 | (0 << 90 OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT), 91 (CS4245_SPI_ADDRESS | CS4245_S 91 (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8); 92 if (ret < 0) 92 if (ret < 0) 93 return ret; 93 return ret; 94 94 95 data->cs4245_shadow[addr] = oxygen_rea 95 data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1); 96 96 97 return 0; 97 return 0; 98 } 98 } 99 99 100 int cs4245_shadow_control(struct oxygen *chip, 100 int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op) 101 { 101 { 102 struct dg *data = chip->model_data; 102 struct dg *data = chip->model_data; 103 unsigned char addr; 103 unsigned char addr; 104 int ret; 104 int ret; 105 105 106 for (addr = 1; addr < ARRAY_SIZE(data- 106 for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) { 107 ret = (op == CS4245_SAVE_TO_SH 107 ret = (op == CS4245_SAVE_TO_SHADOW ? 108 cs4245_read_spi(chip, 108 cs4245_read_spi(chip, addr) : 109 cs4245_write_spi(chip, 109 cs4245_write_spi(chip, addr)); 110 if (ret < 0) 110 if (ret < 0) 111 return ret; 111 return ret; 112 } 112 } 113 return 0; 113 return 0; 114 } 114 } 115 115 116 static void cs4245_init(struct oxygen *chip) 116 static void cs4245_init(struct oxygen *chip) 117 { 117 { 118 struct dg *data = chip->model_data; 118 struct dg *data = chip->model_data; 119 119 120 /* save the initial state: codec versi 120 /* save the initial state: codec version, registers */ 121 cs4245_shadow_control(chip, CS4245_SAV 121 cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW); 122 122 123 /* 123 /* 124 * Power up the CODEC internals, enabl 124 * Power up the CODEC internals, enable soft ramp & zero cross, work in 125 * async. mode, enable aux output from 125 * async. mode, enable aux output from DAC. Invert DAC output as in the 126 * Windows driver. 126 * Windows driver. 127 */ 127 */ 128 data->cs4245_shadow[CS4245_POWER_CTRL] 128 data->cs4245_shadow[CS4245_POWER_CTRL] = 0; 129 data->cs4245_shadow[CS4245_SIGNAL_SEL] 129 data->cs4245_shadow[CS4245_SIGNAL_SEL] = 130 CS4245_A_OUT_SEL_DAC | CS4245_ 130 CS4245_A_OUT_SEL_DAC | CS4245_ASYNCH; 131 data->cs4245_shadow[CS4245_DAC_CTRL_1] 131 data->cs4245_shadow[CS4245_DAC_CTRL_1] = 132 CS4245_DAC_FM_SINGLE | CS4245_ 132 CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST; 133 data->cs4245_shadow[CS4245_DAC_CTRL_2] 133 data->cs4245_shadow[CS4245_DAC_CTRL_2] = 134 CS4245_DAC_SOFT | CS4245_DAC_Z 134 CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC; 135 data->cs4245_shadow[CS4245_ADC_CTRL] = 135 data->cs4245_shadow[CS4245_ADC_CTRL] = 136 CS4245_ADC_FM_SINGLE | CS4245_ 136 CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST; 137 data->cs4245_shadow[CS4245_ANALOG_IN] 137 data->cs4245_shadow[CS4245_ANALOG_IN] = 138 CS4245_PGA_SOFT | CS4245_PGA_Z 138 CS4245_PGA_SOFT | CS4245_PGA_ZERO; 139 data->cs4245_shadow[CS4245_PGA_B_CTRL] 139 data->cs4245_shadow[CS4245_PGA_B_CTRL] = 0; 140 data->cs4245_shadow[CS4245_PGA_A_CTRL] 140 data->cs4245_shadow[CS4245_PGA_A_CTRL] = 0; 141 data->cs4245_shadow[CS4245_DAC_A_CTRL] 141 data->cs4245_shadow[CS4245_DAC_A_CTRL] = 8; 142 data->cs4245_shadow[CS4245_DAC_B_CTRL] 142 data->cs4245_shadow[CS4245_DAC_B_CTRL] = 8; 143 143 144 cs4245_shadow_control(chip, CS4245_LOA 144 cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW); 145 snd_component_add(chip->card, "CS4245" 145 snd_component_add(chip->card, "CS4245"); 146 } 146 } 147 147 148 void dg_init(struct oxygen *chip) 148 void dg_init(struct oxygen *chip) 149 { 149 { 150 struct dg *data = chip->model_data; 150 struct dg *data = chip->model_data; 151 151 152 data->output_sel = PLAYBACK_DST_HP_FP; 152 data->output_sel = PLAYBACK_DST_HP_FP; 153 data->input_sel = CAPTURE_SRC_MIC; 153 data->input_sel = CAPTURE_SRC_MIC; 154 154 155 cs4245_init(chip); 155 cs4245_init(chip); 156 oxygen_write16(chip, OXYGEN_GPIO_CONTR 156 oxygen_write16(chip, OXYGEN_GPIO_CONTROL, 157 GPIO_OUTPUT_ENABLE | GP 157 GPIO_OUTPUT_ENABLE | GPIO_HP_REAR | GPIO_INPUT_ROUTE); 158 /* anti-pop delay, wait some time befo 158 /* anti-pop delay, wait some time before enabling the output */ 159 msleep(2500); 159 msleep(2500); 160 oxygen_write16(chip, OXYGEN_GPIO_DATA, 160 oxygen_write16(chip, OXYGEN_GPIO_DATA, 161 GPIO_OUTPUT_ENABLE | GP 161 GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE); 162 } 162 } 163 163 164 void dg_cleanup(struct oxygen *chip) 164 void dg_cleanup(struct oxygen *chip) 165 { 165 { 166 oxygen_clear_bits16(chip, OXYGEN_GPIO_ 166 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 167 } 167 } 168 168 169 void dg_suspend(struct oxygen *chip) 169 void dg_suspend(struct oxygen *chip) 170 { 170 { 171 dg_cleanup(chip); 171 dg_cleanup(chip); 172 } 172 } 173 173 174 void dg_resume(struct oxygen *chip) 174 void dg_resume(struct oxygen *chip) 175 { 175 { 176 cs4245_shadow_control(chip, CS4245_LOA 176 cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW); 177 msleep(2500); 177 msleep(2500); 178 oxygen_set_bits16(chip, OXYGEN_GPIO_DA 178 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 179 } 179 } 180 180 181 void set_cs4245_dac_params(struct oxygen *chip 181 void set_cs4245_dac_params(struct oxygen *chip, 182 struct snd_p 182 struct snd_pcm_hw_params *params) 183 { 183 { 184 struct dg *data = chip->model_data; 184 struct dg *data = chip->model_data; 185 unsigned char dac_ctrl; 185 unsigned char dac_ctrl; 186 unsigned char mclk_freq; 186 unsigned char mclk_freq; 187 187 188 dac_ctrl = data->cs4245_shadow[CS4245_ 188 dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK; 189 mclk_freq = data->cs4245_shadow[CS4245 189 mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK; 190 if (params_rate(params) <= 50000) { 190 if (params_rate(params) <= 50000) { 191 dac_ctrl |= CS4245_DAC_FM_SING 191 dac_ctrl |= CS4245_DAC_FM_SINGLE; 192 mclk_freq |= CS4245_MCLK_1 << 192 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT; 193 } else if (params_rate(params) <= 1000 193 } else if (params_rate(params) <= 100000) { 194 dac_ctrl |= CS4245_DAC_FM_DOUB 194 dac_ctrl |= CS4245_DAC_FM_DOUBLE; 195 mclk_freq |= CS4245_MCLK_1 << 195 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT; 196 } else { 196 } else { 197 dac_ctrl |= CS4245_DAC_FM_QUAD 197 dac_ctrl |= CS4245_DAC_FM_QUAD; 198 mclk_freq |= CS4245_MCLK_2 << 198 mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT; 199 } 199 } 200 data->cs4245_shadow[CS4245_DAC_CTRL_1] 200 data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl; 201 data->cs4245_shadow[CS4245_MCLK_FREQ] 201 data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq; 202 cs4245_write_spi(chip, CS4245_DAC_CTRL 202 cs4245_write_spi(chip, CS4245_DAC_CTRL_1); 203 cs4245_write_spi(chip, CS4245_MCLK_FRE 203 cs4245_write_spi(chip, CS4245_MCLK_FREQ); 204 } 204 } 205 205 206 void set_cs4245_adc_params(struct oxygen *chip 206 void set_cs4245_adc_params(struct oxygen *chip, 207 struct snd_p 207 struct snd_pcm_hw_params *params) 208 { 208 { 209 struct dg *data = chip->model_data; 209 struct dg *data = chip->model_data; 210 unsigned char adc_ctrl; 210 unsigned char adc_ctrl; 211 unsigned char mclk_freq; 211 unsigned char mclk_freq; 212 212 213 adc_ctrl = data->cs4245_shadow[CS4245_ 213 adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK; 214 mclk_freq = data->cs4245_shadow[CS4245 214 mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK; 215 if (params_rate(params) <= 50000) { 215 if (params_rate(params) <= 50000) { 216 adc_ctrl |= CS4245_ADC_FM_SING 216 adc_ctrl |= CS4245_ADC_FM_SINGLE; 217 mclk_freq |= CS4245_MCLK_1 << 217 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT; 218 } else if (params_rate(params) <= 1000 218 } else if (params_rate(params) <= 100000) { 219 adc_ctrl |= CS4245_ADC_FM_DOUB 219 adc_ctrl |= CS4245_ADC_FM_DOUBLE; 220 mclk_freq |= CS4245_MCLK_1 << 220 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT; 221 } else { 221 } else { 222 adc_ctrl |= CS4245_ADC_FM_QUAD 222 adc_ctrl |= CS4245_ADC_FM_QUAD; 223 mclk_freq |= CS4245_MCLK_2 << 223 mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT; 224 } 224 } 225 data->cs4245_shadow[CS4245_ADC_CTRL] = 225 data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl; 226 data->cs4245_shadow[CS4245_MCLK_FREQ] 226 data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq; 227 cs4245_write_spi(chip, CS4245_ADC_CTRL 227 cs4245_write_spi(chip, CS4245_ADC_CTRL); 228 cs4245_write_spi(chip, CS4245_MCLK_FRE 228 cs4245_write_spi(chip, CS4245_MCLK_FREQ); 229 } 229 } 230 230 231 static inline unsigned int shift_bits(unsigned 231 static inline unsigned int shift_bits(unsigned int value, 232 unsigned 232 unsigned int shift_from, 233 unsigned 233 unsigned int shift_to, 234 unsigned 234 unsigned int mask) 235 { 235 { 236 if (shift_from < shift_to) 236 if (shift_from < shift_to) 237 return (value << (shift_to - s 237 return (value << (shift_to - shift_from)) & mask; 238 else 238 else 239 return (value >> (shift_from - 239 return (value >> (shift_from - shift_to)) & mask; 240 } 240 } 241 241 242 unsigned int adjust_dg_dac_routing(struct oxyg 242 unsigned int adjust_dg_dac_routing(struct oxygen *chip, 243 unsi 243 unsigned int play_routing) 244 { 244 { 245 struct dg *data = chip->model_data; 245 struct dg *data = chip->model_data; 246 246 247 switch (data->output_sel) { 247 switch (data->output_sel) { 248 case PLAYBACK_DST_HP: 248 case PLAYBACK_DST_HP: 249 case PLAYBACK_DST_HP_FP: 249 case PLAYBACK_DST_HP_FP: 250 oxygen_write8_masked(chip, OXY 250 oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING, 251 OXYGEN_PLAY_MUTE23 | O 251 OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 | 252 OXYGEN_PLAY_MUTE67, OX 252 OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK); 253 break; 253 break; 254 case PLAYBACK_DST_MULTICH: 254 case PLAYBACK_DST_MULTICH: 255 oxygen_write8_masked(chip, OXY 255 oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING, 256 OXYGEN_PLAY_MUTE01, OX 256 OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK); 257 break; 257 break; 258 } 258 } 259 return (play_routing & OXYGEN_PLAY_DAC 259 return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) | 260 shift_bits(play_routing, 260 shift_bits(play_routing, 261 OXYGEN_PLAY_DAC2_SOU 261 OXYGEN_PLAY_DAC2_SOURCE_SHIFT, 262 OXYGEN_PLAY_DAC1_SOU 262 OXYGEN_PLAY_DAC1_SOURCE_SHIFT, 263 OXYGEN_PLAY_DAC1_SOU 263 OXYGEN_PLAY_DAC1_SOURCE_MASK) | 264 shift_bits(play_routing, 264 shift_bits(play_routing, 265 OXYGEN_PLAY_DAC1_SOU 265 OXYGEN_PLAY_DAC1_SOURCE_SHIFT, 266 OXYGEN_PLAY_DAC2_SOU 266 OXYGEN_PLAY_DAC2_SOURCE_SHIFT, 267 OXYGEN_PLAY_DAC2_SOU 267 OXYGEN_PLAY_DAC2_SOURCE_MASK) | 268 shift_bits(play_routing, 268 shift_bits(play_routing, 269 OXYGEN_PLAY_DAC0_SOU 269 OXYGEN_PLAY_DAC0_SOURCE_SHIFT, 270 OXYGEN_PLAY_DAC3_SOU 270 OXYGEN_PLAY_DAC3_SOURCE_SHIFT, 271 OXYGEN_PLAY_DAC3_SOU 271 OXYGEN_PLAY_DAC3_SOURCE_MASK); 272 } 272 } 273 273 274 void dump_cs4245_registers(struct oxygen *chip 274 void dump_cs4245_registers(struct oxygen *chip, 275 struct snd_i 275 struct snd_info_buffer *buffer) 276 { 276 { 277 struct dg *data = chip->model_data; 277 struct dg *data = chip->model_data; 278 unsigned int addr; 278 unsigned int addr; 279 279 280 snd_iprintf(buffer, "\nCS4245:"); 280 snd_iprintf(buffer, "\nCS4245:"); 281 cs4245_read_spi(chip, CS4245_INT_STATU 281 cs4245_read_spi(chip, CS4245_INT_STATUS); 282 for (addr = 1; addr < ARRAY_SIZE(data- 282 for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) 283 snd_iprintf(buffer, " %02x", d 283 snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]); 284 snd_iprintf(buffer, "\n"); 284 snd_iprintf(buffer, "\n"); 285 } 285 } 286 286
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.