1 // SPDX-License-Identifier: GPL-2.0-only
3 * card driver for the Xonar DG/DGX
5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
6 * Copyright (c) Roman Volkov <v1ron@mail.ru>
13 * CS4245 and CS4361 both will mute all outputs if any clock ratio
22 * I²S 2 -> CS4361 (center/LFE)
23 * I²S 3 -> CS4361 (surround)
24 * I²S 4 -> CS4361 (front)
29 * GPIO 4 <- headphone detect
30 * GPIO 5 -> enable ADC analog circuit for the left channel
31 * GPIO 6 -> enable ADC analog circuit for the right channel
32 * GPIO 7 -> switch green rear output jack between CS4245 and the first
33 * channel of CS4361 (mechanical relay)
34 * GPIO 8 -> enable output to speakers
40 * input 2 <- front mic
42 * DAC out -> headphones
43 * aux out -> front panel headphones
46 #include <linux/pci.h>
47 #include <linux/delay.h>
48 #include <sound/control.h>
49 #include <sound/core.h>
50 #include <sound/info.h>
51 #include <sound/pcm.h>
52 #include <sound/tlv.h>
57 int cs4245_write_spi(struct oxygen
*chip
, u8 reg
)
59 struct dg
*data
= chip
->model_data
;
63 packet
|= (CS4245_SPI_ADDRESS
| CS4245_SPI_WRITE
) << 16;
64 packet
|= data
->cs4245_shadow
[reg
];
66 return oxygen_write_spi(chip
, OXYGEN_SPI_TRIGGER
|
67 OXYGEN_SPI_DATA_LENGTH_3
|
68 OXYGEN_SPI_CLOCK_1280
|
69 (0 << OXYGEN_SPI_CODEC_SHIFT
) |
70 OXYGEN_SPI_CEN_LATCH_CLOCK_HI
,
74 int cs4245_read_spi(struct oxygen
*chip
, u8 addr
)
76 struct dg
*data
= chip
->model_data
;
79 ret
= oxygen_write_spi(chip
, OXYGEN_SPI_TRIGGER
|
80 OXYGEN_SPI_DATA_LENGTH_2
|
81 OXYGEN_SPI_CEN_LATCH_CLOCK_HI
|
82 OXYGEN_SPI_CLOCK_1280
| (0 << OXYGEN_SPI_CODEC_SHIFT
),
83 ((CS4245_SPI_ADDRESS
| CS4245_SPI_WRITE
) << 8) | addr
);
87 ret
= oxygen_write_spi(chip
, OXYGEN_SPI_TRIGGER
|
88 OXYGEN_SPI_DATA_LENGTH_2
|
89 OXYGEN_SPI_CEN_LATCH_CLOCK_HI
|
90 OXYGEN_SPI_CLOCK_1280
| (0 << OXYGEN_SPI_CODEC_SHIFT
),
91 (CS4245_SPI_ADDRESS
| CS4245_SPI_READ
) << 8);
95 data
->cs4245_shadow
[addr
] = oxygen_read8(chip
, OXYGEN_SPI_DATA1
);
100 int cs4245_shadow_control(struct oxygen
*chip
, enum cs4245_shadow_operation op
)
102 struct dg
*data
= chip
->model_data
;
106 for (addr
= 1; addr
< ARRAY_SIZE(data
->cs4245_shadow
); addr
++) {
107 ret
= (op
== CS4245_SAVE_TO_SHADOW
?
108 cs4245_read_spi(chip
, addr
) :
109 cs4245_write_spi(chip
, addr
));
116 static void cs4245_init(struct oxygen
*chip
)
118 struct dg
*data
= chip
->model_data
;
120 /* save the initial state: codec version, registers */
121 cs4245_shadow_control(chip
, CS4245_SAVE_TO_SHADOW
);
124 * Power up the CODEC internals, enable soft ramp & zero cross, work in
125 * async. mode, enable aux output from DAC. Invert DAC output as in the
128 data
->cs4245_shadow
[CS4245_POWER_CTRL
] = 0;
129 data
->cs4245_shadow
[CS4245_SIGNAL_SEL
] =
130 CS4245_A_OUT_SEL_DAC
| CS4245_ASYNCH
;
131 data
->cs4245_shadow
[CS4245_DAC_CTRL_1
] =
132 CS4245_DAC_FM_SINGLE
| CS4245_DAC_DIF_LJUST
;
133 data
->cs4245_shadow
[CS4245_DAC_CTRL_2
] =
134 CS4245_DAC_SOFT
| CS4245_DAC_ZERO
| CS4245_INVERT_DAC
;
135 data
->cs4245_shadow
[CS4245_ADC_CTRL
] =
136 CS4245_ADC_FM_SINGLE
| CS4245_ADC_DIF_LJUST
;
137 data
->cs4245_shadow
[CS4245_ANALOG_IN
] =
138 CS4245_PGA_SOFT
| CS4245_PGA_ZERO
;
139 data
->cs4245_shadow
[CS4245_PGA_B_CTRL
] = 0;
140 data
->cs4245_shadow
[CS4245_PGA_A_CTRL
] = 0;
141 data
->cs4245_shadow
[CS4245_DAC_A_CTRL
] = 8;
142 data
->cs4245_shadow
[CS4245_DAC_B_CTRL
] = 8;
144 cs4245_shadow_control(chip
, CS4245_LOAD_FROM_SHADOW
);
145 snd_component_add(chip
->card
, "CS4245");
148 void dg_init(struct oxygen
*chip
)
150 struct dg
*data
= chip
->model_data
;
152 data
->output_sel
= PLAYBACK_DST_HP_FP
;
153 data
->input_sel
= CAPTURE_SRC_MIC
;
156 oxygen_write16(chip
, OXYGEN_GPIO_CONTROL
,
157 GPIO_OUTPUT_ENABLE
| GPIO_HP_REAR
| GPIO_INPUT_ROUTE
);
158 /* anti-pop delay, wait some time before enabling the output */
160 oxygen_write16(chip
, OXYGEN_GPIO_DATA
,
161 GPIO_OUTPUT_ENABLE
| GPIO_INPUT_ROUTE
);
164 void dg_cleanup(struct oxygen
*chip
)
166 oxygen_clear_bits16(chip
, OXYGEN_GPIO_DATA
, GPIO_OUTPUT_ENABLE
);
169 void dg_suspend(struct oxygen
*chip
)
174 void dg_resume(struct oxygen
*chip
)
176 cs4245_shadow_control(chip
, CS4245_LOAD_FROM_SHADOW
);
178 oxygen_set_bits16(chip
, OXYGEN_GPIO_DATA
, GPIO_OUTPUT_ENABLE
);
181 void set_cs4245_dac_params(struct oxygen
*chip
,
182 struct snd_pcm_hw_params
*params
)
184 struct dg
*data
= chip
->model_data
;
185 unsigned char dac_ctrl
;
186 unsigned char mclk_freq
;
188 dac_ctrl
= data
->cs4245_shadow
[CS4245_DAC_CTRL_1
] & ~CS4245_DAC_FM_MASK
;
189 mclk_freq
= data
->cs4245_shadow
[CS4245_MCLK_FREQ
] & ~CS4245_MCLK1_MASK
;
190 if (params_rate(params
) <= 50000) {
191 dac_ctrl
|= CS4245_DAC_FM_SINGLE
;
192 mclk_freq
|= CS4245_MCLK_1
<< CS4245_MCLK1_SHIFT
;
193 } else if (params_rate(params
) <= 100000) {
194 dac_ctrl
|= CS4245_DAC_FM_DOUBLE
;
195 mclk_freq
|= CS4245_MCLK_1
<< CS4245_MCLK1_SHIFT
;
197 dac_ctrl
|= CS4245_DAC_FM_QUAD
;
198 mclk_freq
|= CS4245_MCLK_2
<< CS4245_MCLK1_SHIFT
;
200 data
->cs4245_shadow
[CS4245_DAC_CTRL_1
] = dac_ctrl
;
201 data
->cs4245_shadow
[CS4245_MCLK_FREQ
] = mclk_freq
;
202 cs4245_write_spi(chip
, CS4245_DAC_CTRL_1
);
203 cs4245_write_spi(chip
, CS4245_MCLK_FREQ
);
206 void set_cs4245_adc_params(struct oxygen
*chip
,
207 struct snd_pcm_hw_params
*params
)
209 struct dg
*data
= chip
->model_data
;
210 unsigned char adc_ctrl
;
211 unsigned char mclk_freq
;
213 adc_ctrl
= data
->cs4245_shadow
[CS4245_ADC_CTRL
] & ~CS4245_ADC_FM_MASK
;
214 mclk_freq
= data
->cs4245_shadow
[CS4245_MCLK_FREQ
] & ~CS4245_MCLK2_MASK
;
215 if (params_rate(params
) <= 50000) {
216 adc_ctrl
|= CS4245_ADC_FM_SINGLE
;
217 mclk_freq
|= CS4245_MCLK_1
<< CS4245_MCLK2_SHIFT
;
218 } else if (params_rate(params
) <= 100000) {
219 adc_ctrl
|= CS4245_ADC_FM_DOUBLE
;
220 mclk_freq
|= CS4245_MCLK_1
<< CS4245_MCLK2_SHIFT
;
222 adc_ctrl
|= CS4245_ADC_FM_QUAD
;
223 mclk_freq
|= CS4245_MCLK_2
<< CS4245_MCLK2_SHIFT
;
225 data
->cs4245_shadow
[CS4245_ADC_CTRL
] = adc_ctrl
;
226 data
->cs4245_shadow
[CS4245_MCLK_FREQ
] = mclk_freq
;
227 cs4245_write_spi(chip
, CS4245_ADC_CTRL
);
228 cs4245_write_spi(chip
, CS4245_MCLK_FREQ
);
231 static inline unsigned int shift_bits(unsigned int value
,
232 unsigned int shift_from
,
233 unsigned int shift_to
,
236 if (shift_from
< shift_to
)
237 return (value
<< (shift_to
- shift_from
)) & mask
;
239 return (value
>> (shift_from
- shift_to
)) & mask
;
242 unsigned int adjust_dg_dac_routing(struct oxygen
*chip
,
243 unsigned int play_routing
)
245 struct dg
*data
= chip
->model_data
;
247 switch (data
->output_sel
) {
248 case PLAYBACK_DST_HP
:
249 case PLAYBACK_DST_HP_FP
:
250 oxygen_write8_masked(chip
, OXYGEN_PLAY_ROUTING
,
251 OXYGEN_PLAY_MUTE23
| OXYGEN_PLAY_MUTE45
|
252 OXYGEN_PLAY_MUTE67
, OXYGEN_PLAY_MUTE_MASK
);
254 case PLAYBACK_DST_MULTICH
:
255 oxygen_write8_masked(chip
, OXYGEN_PLAY_ROUTING
,
256 OXYGEN_PLAY_MUTE01
, OXYGEN_PLAY_MUTE_MASK
);
259 return (play_routing
& OXYGEN_PLAY_DAC0_SOURCE_MASK
) |
260 shift_bits(play_routing
,
261 OXYGEN_PLAY_DAC2_SOURCE_SHIFT
,
262 OXYGEN_PLAY_DAC1_SOURCE_SHIFT
,
263 OXYGEN_PLAY_DAC1_SOURCE_MASK
) |
264 shift_bits(play_routing
,
265 OXYGEN_PLAY_DAC1_SOURCE_SHIFT
,
266 OXYGEN_PLAY_DAC2_SOURCE_SHIFT
,
267 OXYGEN_PLAY_DAC2_SOURCE_MASK
) |
268 shift_bits(play_routing
,
269 OXYGEN_PLAY_DAC0_SOURCE_SHIFT
,
270 OXYGEN_PLAY_DAC3_SOURCE_SHIFT
,
271 OXYGEN_PLAY_DAC3_SOURCE_MASK
);
274 void dump_cs4245_registers(struct oxygen
*chip
,
275 struct snd_info_buffer
*buffer
)
277 struct dg
*data
= chip
->model_data
;
280 snd_iprintf(buffer
, "\nCS4245:");
281 cs4245_read_spi(chip
, CS4245_INT_STATUS
);
282 for (addr
= 1; addr
< ARRAY_SIZE(data
->cs4245_shadow
); addr
++)
283 snd_iprintf(buffer
, " %02x", data
->cs4245_shadow
[addr
]);
284 snd_iprintf(buffer
, "\n");