2 * card driver for the Xonar DG/DGX
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 * Copyright (c) Roman Volkov <v1ron@mail.ru>
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.
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.
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/>.
23 * CS4245 and CS4361 both will mute all outputs if any clock ratio
32 * I²S 2 -> CS4361 (center/LFE)
33 * I²S 3 -> CS4361 (surround)
34 * I²S 4 -> CS4361 (front)
39 * GPIO 4 <- headphone detect
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)
44 * GPIO 8 -> enable output to speakers
50 * input 2 <- front mic
52 * DAC out -> headphones
53 * aux out -> front panel headphones
56 #include <linux/pci.h>
57 #include <linux/delay.h>
58 #include <sound/control.h>
59 #include <sound/core.h>
60 #include <sound/info.h>
61 #include <sound/pcm.h>
62 #include <sound/tlv.h>
67 int cs4245_write_spi(struct oxygen *chip, u8 reg)
69 struct dg *data = chip->model_data;
73 packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16;
74 packet |= data->cs4245_shadow[reg];
76 return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
77 OXYGEN_SPI_DATA_LENGTH_3 |
78 OXYGEN_SPI_CLOCK_1280 |
79 (0 << OXYGEN_SPI_CODEC_SHIFT) |
80 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
84 int cs4245_read_spi(struct oxygen *chip, u8 addr)
86 struct dg *data = chip->model_data;
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_WRITE) << 8) | addr);
97 ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
98 OXYGEN_SPI_DATA_LENGTH_2 |
99 OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
100 OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
101 (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8);
105 data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1);
110 int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op)
112 struct dg *data = chip->model_data;
116 for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) {
117 ret = (op == CS4245_SAVE_TO_SHADOW ?
118 cs4245_read_spi(chip, addr) :
119 cs4245_write_spi(chip, addr));
126 void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
128 struct dg *data = chip->model_data;
130 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
131 OXYGEN_SPI_DATA_LENGTH_3 |
132 OXYGEN_SPI_CLOCK_1280 |
133 (0 << OXYGEN_SPI_CODEC_SHIFT) |
134 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
135 CS4245_SPI_ADDRESS_S |
138 data->cs4245_shadow[reg] = value;
141 void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
143 struct dg *data = chip->model_data;
145 if (value != data->cs4245_shadow[reg])
146 cs4245_write(chip, reg, value);
149 static void cs4245_init(struct oxygen *chip)
151 struct dg *data = chip->model_data;
153 /* save the initial state: codec version, registers */
154 cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW);
157 * Power up the CODEC internals, enable soft ramp & zero cross, work in
158 * async. mode, enable aux output from DAC. Invert DAC output as in the
161 data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
162 data->cs4245_shadow[CS4245_SIGNAL_SEL] =
163 CS4245_A_OUT_SEL_DAC | CS4245_ASYNCH;
164 data->cs4245_shadow[CS4245_DAC_CTRL_1] =
165 CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
166 data->cs4245_shadow[CS4245_DAC_CTRL_2] =
167 CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC;
168 data->cs4245_shadow[CS4245_ADC_CTRL] =
169 CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
170 data->cs4245_shadow[CS4245_ANALOG_IN] =
171 CS4245_PGA_SOFT | CS4245_PGA_ZERO;
172 data->cs4245_shadow[CS4245_PGA_B_CTRL] = 0;
173 data->cs4245_shadow[CS4245_PGA_A_CTRL] = 0;
174 data->cs4245_shadow[CS4245_DAC_A_CTRL] = 4;
175 data->cs4245_shadow[CS4245_DAC_B_CTRL] = 4;
177 cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
178 snd_component_add(chip->card, "CS4245");
181 void dg_init(struct oxygen *chip)
183 struct dg *data = chip->model_data;
185 data->output_sel = 0;
187 data->hp_vol_att = 2 * 16;
190 oxygen_write16(chip, OXYGEN_GPIO_CONTROL,
191 GPIO_OUTPUT_ENABLE | GPIO_HP_REAR | GPIO_INPUT_ROUTE);
192 oxygen_write16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);
193 msleep(2500); /* anti-pop delay */
194 oxygen_write16(chip, OXYGEN_GPIO_DATA,
195 GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE);
198 void dg_cleanup(struct oxygen *chip)
200 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
203 void dg_suspend(struct oxygen *chip)
208 void dg_resume(struct oxygen *chip)
210 cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
212 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
215 void set_cs4245_dac_params(struct oxygen *chip,
216 struct snd_pcm_hw_params *params)
218 struct dg *data = chip->model_data;
219 unsigned char dac_ctrl;
220 unsigned char mclk_freq;
222 dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
223 mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK;
224 if (params_rate(params) <= 50000) {
225 dac_ctrl |= CS4245_DAC_FM_SINGLE;
226 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
227 } else if (params_rate(params) <= 100000) {
228 dac_ctrl |= CS4245_DAC_FM_DOUBLE;
229 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
231 dac_ctrl |= CS4245_DAC_FM_QUAD;
232 mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT;
234 data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl;
235 data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
236 cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
237 cs4245_write_spi(chip, CS4245_MCLK_FREQ);
240 void set_cs4245_adc_params(struct oxygen *chip,
241 struct snd_pcm_hw_params *params)
243 struct dg *data = chip->model_data;
244 unsigned char adc_ctrl;
245 unsigned char mclk_freq;
247 adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
248 mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK;
249 if (params_rate(params) <= 50000) {
250 adc_ctrl |= CS4245_ADC_FM_SINGLE;
251 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
252 } else if (params_rate(params) <= 100000) {
253 adc_ctrl |= CS4245_ADC_FM_DOUBLE;
254 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
256 adc_ctrl |= CS4245_ADC_FM_QUAD;
257 mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT;
259 data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl;
260 data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
261 cs4245_write_spi(chip, CS4245_ADC_CTRL);
262 cs4245_write_spi(chip, CS4245_MCLK_FREQ);
265 unsigned int adjust_dg_dac_routing(struct oxygen *chip,
266 unsigned int play_routing)
268 struct dg *data = chip->model_data;
269 unsigned int routing = 0;
271 switch (data->output_sel) {
272 case PLAYBACK_DST_HP:
273 case PLAYBACK_DST_HP_FP:
274 oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
275 OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 |
276 OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
278 case PLAYBACK_DST_MULTICH:
279 routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
280 (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
281 (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
282 (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
283 oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
284 OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
290 void dump_cs4245_registers(struct oxygen *chip,
291 struct snd_info_buffer *buffer)
293 struct dg *data = chip->model_data;
296 snd_iprintf(buffer, "\nCS4245:");
297 cs4245_read_spi(chip, CS4245_INT_STATUS);
298 for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++)
299 snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]);
300 snd_iprintf(buffer, "\n");