1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * card driver for models with CS4398/CS4362A DACs (Xonar D1/DX) |
4 | * |
5 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
6 | */ |
7 | |
8 | /* |
9 | * Xonar D1/DX |
10 | * ----------- |
11 | * |
12 | * CMI8788: |
13 | * |
14 | * I²C <-> CS4398 (addr 1001111) (front) |
15 | * <-> CS4362A (addr 0011000) (surround, center/LFE, back) |
16 | * |
17 | * GPI 0 <- external power present (DX only) |
18 | * |
19 | * GPIO 0 -> enable output to speakers |
20 | * GPIO 1 -> route output to front panel |
21 | * GPIO 2 -> M0 of CS5361 |
22 | * GPIO 3 -> M1 of CS5361 |
23 | * GPIO 6 -> ? |
24 | * GPIO 7 -> ? |
25 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) |
26 | * |
27 | * CM9780: |
28 | * |
29 | * LINE_OUT -> input of ADC |
30 | * |
31 | * AUX_IN <- aux |
32 | * MIC_IN <- mic |
33 | * FMIC_IN <- front mic |
34 | * |
35 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input |
36 | */ |
37 | |
38 | #include <linux/pci.h> |
39 | #include <linux/delay.h> |
40 | #include <sound/ac97_codec.h> |
41 | #include <sound/control.h> |
42 | #include <sound/core.h> |
43 | #include <sound/pcm.h> |
44 | #include <sound/pcm_params.h> |
45 | #include <sound/tlv.h> |
46 | #include "xonar.h" |
47 | #include "cm9780.h" |
48 | #include "cs4398.h" |
49 | #include "cs4362a.h" |
50 | |
51 | #define GPI_EXT_POWER 0x01 |
52 | #define GPIO_D1_OUTPUT_ENABLE 0x0001 |
53 | #define GPIO_D1_FRONT_PANEL 0x0002 |
54 | #define GPIO_D1_MAGIC 0x00c0 |
55 | #define GPIO_D1_INPUT_ROUTE 0x0100 |
56 | |
57 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ |
58 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ |
59 | |
60 | struct xonar_cs43xx { |
61 | struct xonar_generic generic; |
62 | u8 cs4398_regs[8]; |
63 | u8 cs4362a_regs[15]; |
64 | }; |
65 | |
66 | static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) |
67 | { |
68 | struct xonar_cs43xx *data = chip->model_data; |
69 | |
70 | oxygen_write_i2c(chip, I2C_DEVICE_CS4398, map: reg, data: value); |
71 | if (reg < ARRAY_SIZE(data->cs4398_regs)) |
72 | data->cs4398_regs[reg] = value; |
73 | } |
74 | |
75 | static void cs4398_write_cached(struct oxygen *chip, u8 reg, u8 value) |
76 | { |
77 | struct xonar_cs43xx *data = chip->model_data; |
78 | |
79 | if (value != data->cs4398_regs[reg]) |
80 | cs4398_write(chip, reg, value); |
81 | } |
82 | |
83 | static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) |
84 | { |
85 | struct xonar_cs43xx *data = chip->model_data; |
86 | |
87 | oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, map: reg, data: value); |
88 | if (reg < ARRAY_SIZE(data->cs4362a_regs)) |
89 | data->cs4362a_regs[reg] = value; |
90 | } |
91 | |
92 | static void cs4362a_write_cached(struct oxygen *chip, u8 reg, u8 value) |
93 | { |
94 | struct xonar_cs43xx *data = chip->model_data; |
95 | |
96 | if (value != data->cs4362a_regs[reg]) |
97 | cs4362a_write(chip, reg, value); |
98 | } |
99 | |
100 | static void cs43xx_registers_init(struct oxygen *chip) |
101 | { |
102 | struct xonar_cs43xx *data = chip->model_data; |
103 | unsigned int i; |
104 | |
105 | /* set CPEN (control port mode) and power down */ |
106 | cs4398_write(chip, reg: 8, CS4398_CPEN | CS4398_PDN); |
107 | cs4362a_write(chip, reg: 0x01, CS4362A_PDN | CS4362A_CPEN); |
108 | /* configure */ |
109 | cs4398_write(chip, reg: 2, value: data->cs4398_regs[2]); |
110 | cs4398_write(chip, reg: 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); |
111 | cs4398_write(chip, reg: 4, value: data->cs4398_regs[4]); |
112 | cs4398_write(chip, reg: 5, value: data->cs4398_regs[5]); |
113 | cs4398_write(chip, reg: 6, value: data->cs4398_regs[6]); |
114 | cs4398_write(chip, reg: 7, value: data->cs4398_regs[7]); |
115 | cs4362a_write(chip, reg: 0x02, CS4362A_DIF_LJUST); |
116 | cs4362a_write(chip, reg: 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | |
117 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); |
118 | cs4362a_write(chip, reg: 0x04, value: data->cs4362a_regs[0x04]); |
119 | cs4362a_write(chip, reg: 0x05, value: 0); |
120 | for (i = 6; i <= 14; ++i) |
121 | cs4362a_write(chip, reg: i, value: data->cs4362a_regs[i]); |
122 | /* clear power down */ |
123 | cs4398_write(chip, reg: 8, CS4398_CPEN); |
124 | cs4362a_write(chip, reg: 0x01, CS4362A_CPEN); |
125 | } |
126 | |
127 | static void xonar_d1_init(struct oxygen *chip) |
128 | { |
129 | struct xonar_cs43xx *data = chip->model_data; |
130 | |
131 | data->generic.anti_pop_delay = 800; |
132 | data->generic.output_enable_bit = GPIO_D1_OUTPUT_ENABLE; |
133 | data->cs4398_regs[2] = |
134 | CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; |
135 | data->cs4398_regs[4] = CS4398_MUTEP_LOW | |
136 | CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE; |
137 | data->cs4398_regs[5] = 60 * 2; |
138 | data->cs4398_regs[6] = 60 * 2; |
139 | data->cs4398_regs[7] = CS4398_RMP_DN | CS4398_RMP_UP | |
140 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP; |
141 | data->cs4362a_regs[4] = CS4362A_RMP_DN | CS4362A_DEM_NONE; |
142 | data->cs4362a_regs[6] = CS4362A_FM_SINGLE | |
143 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; |
144 | data->cs4362a_regs[7] = 60 | CS4362A_MUTE; |
145 | data->cs4362a_regs[8] = 60 | CS4362A_MUTE; |
146 | data->cs4362a_regs[9] = data->cs4362a_regs[6]; |
147 | data->cs4362a_regs[10] = 60 | CS4362A_MUTE; |
148 | data->cs4362a_regs[11] = 60 | CS4362A_MUTE; |
149 | data->cs4362a_regs[12] = data->cs4362a_regs[6]; |
150 | data->cs4362a_regs[13] = 60 | CS4362A_MUTE; |
151 | data->cs4362a_regs[14] = 60 | CS4362A_MUTE; |
152 | |
153 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, |
154 | OXYGEN_2WIRE_LENGTH_8 | |
155 | OXYGEN_2WIRE_INTERRUPT_MASK | |
156 | OXYGEN_2WIRE_SPEED_FAST); |
157 | |
158 | cs43xx_registers_init(chip); |
159 | |
160 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
161 | GPIO_D1_FRONT_PANEL | |
162 | GPIO_D1_MAGIC | |
163 | GPIO_D1_INPUT_ROUTE); |
164 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, |
165 | GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); |
166 | |
167 | xonar_init_cs53x1(chip); |
168 | xonar_enable_output(chip); |
169 | |
170 | snd_component_add(card: chip->card, component: "CS4398" ); |
171 | snd_component_add(card: chip->card, component: "CS4362A" ); |
172 | snd_component_add(card: chip->card, component: "CS5361" ); |
173 | } |
174 | |
175 | static void xonar_dx_init(struct oxygen *chip) |
176 | { |
177 | struct xonar_cs43xx *data = chip->model_data; |
178 | |
179 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; |
180 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; |
181 | data->generic.ext_power_bit = GPI_EXT_POWER; |
182 | xonar_init_ext_power(chip); |
183 | xonar_d1_init(chip); |
184 | } |
185 | |
186 | static void xonar_d1_cleanup(struct oxygen *chip) |
187 | { |
188 | xonar_disable_output(chip); |
189 | cs4362a_write(chip, reg: 0x01, CS4362A_PDN | CS4362A_CPEN); |
190 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); |
191 | } |
192 | |
193 | static void xonar_d1_suspend(struct oxygen *chip) |
194 | { |
195 | xonar_d1_cleanup(chip); |
196 | } |
197 | |
198 | static void xonar_d1_resume(struct oxygen *chip) |
199 | { |
200 | oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); |
201 | msleep(msecs: 1); |
202 | cs43xx_registers_init(chip); |
203 | xonar_enable_output(chip); |
204 | } |
205 | |
206 | static void set_cs43xx_params(struct oxygen *chip, |
207 | struct snd_pcm_hw_params *params) |
208 | { |
209 | struct xonar_cs43xx *data = chip->model_data; |
210 | u8 cs4398_fm, cs4362a_fm; |
211 | |
212 | if (params_rate(p: params) <= 50000) { |
213 | cs4398_fm = CS4398_FM_SINGLE; |
214 | cs4362a_fm = CS4362A_FM_SINGLE; |
215 | } else if (params_rate(p: params) <= 100000) { |
216 | cs4398_fm = CS4398_FM_DOUBLE; |
217 | cs4362a_fm = CS4362A_FM_DOUBLE; |
218 | } else { |
219 | cs4398_fm = CS4398_FM_QUAD; |
220 | cs4362a_fm = CS4362A_FM_QUAD; |
221 | } |
222 | cs4398_fm |= CS4398_DEM_NONE | CS4398_DIF_LJUST; |
223 | cs4398_write_cached(chip, reg: 2, value: cs4398_fm); |
224 | cs4362a_fm |= data->cs4362a_regs[6] & ~CS4362A_FM_MASK; |
225 | cs4362a_write_cached(chip, reg: 6, value: cs4362a_fm); |
226 | cs4362a_write_cached(chip, reg: 12, value: cs4362a_fm); |
227 | cs4362a_fm &= CS4362A_FM_MASK; |
228 | cs4362a_fm |= data->cs4362a_regs[9] & ~CS4362A_FM_MASK; |
229 | cs4362a_write_cached(chip, reg: 9, value: cs4362a_fm); |
230 | } |
231 | |
232 | static void update_cs4362a_volumes(struct oxygen *chip) |
233 | { |
234 | unsigned int i; |
235 | u8 mute; |
236 | |
237 | mute = chip->dac_mute ? CS4362A_MUTE : 0; |
238 | for (i = 0; i < 6; ++i) |
239 | cs4362a_write_cached(chip, reg: 7 + i + i / 2, |
240 | value: (127 - chip->dac_volume[2 + i]) | mute); |
241 | } |
242 | |
243 | static void update_cs43xx_volume(struct oxygen *chip) |
244 | { |
245 | cs4398_write_cached(chip, reg: 5, value: (127 - chip->dac_volume[0]) * 2); |
246 | cs4398_write_cached(chip, reg: 6, value: (127 - chip->dac_volume[1]) * 2); |
247 | update_cs4362a_volumes(chip); |
248 | } |
249 | |
250 | static void update_cs43xx_mute(struct oxygen *chip) |
251 | { |
252 | u8 reg; |
253 | |
254 | reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; |
255 | if (chip->dac_mute) |
256 | reg |= CS4398_MUTE_B | CS4398_MUTE_A; |
257 | cs4398_write_cached(chip, reg: 4, value: reg); |
258 | update_cs4362a_volumes(chip); |
259 | } |
260 | |
261 | static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed) |
262 | { |
263 | struct xonar_cs43xx *data = chip->model_data; |
264 | u8 reg; |
265 | |
266 | reg = data->cs4362a_regs[9] & ~CS4362A_ATAPI_MASK; |
267 | if (mixed) |
268 | reg |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR; |
269 | else |
270 | reg |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; |
271 | cs4362a_write_cached(chip, reg: 9, value: reg); |
272 | } |
273 | |
274 | static const struct snd_kcontrol_new front_panel_switch = { |
275 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
276 | .name = "Front Panel Playback Switch" , |
277 | .info = snd_ctl_boolean_mono_info, |
278 | .get = xonar_gpio_bit_switch_get, |
279 | .put = xonar_gpio_bit_switch_put, |
280 | .private_value = GPIO_D1_FRONT_PANEL, |
281 | }; |
282 | |
283 | static int rolloff_info(struct snd_kcontrol *ctl, |
284 | struct snd_ctl_elem_info *info) |
285 | { |
286 | static const char *const names[2] = { |
287 | "Fast Roll-off" , "Slow Roll-off" |
288 | }; |
289 | |
290 | return snd_ctl_enum_info(info, channels: 1, items: 2, names); |
291 | } |
292 | |
293 | static int rolloff_get(struct snd_kcontrol *ctl, |
294 | struct snd_ctl_elem_value *value) |
295 | { |
296 | struct oxygen *chip = ctl->private_data; |
297 | struct xonar_cs43xx *data = chip->model_data; |
298 | |
299 | value->value.enumerated.item[0] = |
300 | (data->cs4398_regs[7] & CS4398_FILT_SEL) != 0; |
301 | return 0; |
302 | } |
303 | |
304 | static int rolloff_put(struct snd_kcontrol *ctl, |
305 | struct snd_ctl_elem_value *value) |
306 | { |
307 | struct oxygen *chip = ctl->private_data; |
308 | struct xonar_cs43xx *data = chip->model_data; |
309 | int changed; |
310 | u8 reg; |
311 | |
312 | mutex_lock(&chip->mutex); |
313 | reg = data->cs4398_regs[7]; |
314 | if (value->value.enumerated.item[0]) |
315 | reg |= CS4398_FILT_SEL; |
316 | else |
317 | reg &= ~CS4398_FILT_SEL; |
318 | changed = reg != data->cs4398_regs[7]; |
319 | if (changed) { |
320 | cs4398_write(chip, reg: 7, value: reg); |
321 | if (reg & CS4398_FILT_SEL) |
322 | reg = data->cs4362a_regs[0x04] | CS4362A_FILT_SEL; |
323 | else |
324 | reg = data->cs4362a_regs[0x04] & ~CS4362A_FILT_SEL; |
325 | cs4362a_write(chip, reg: 0x04, value: reg); |
326 | } |
327 | mutex_unlock(lock: &chip->mutex); |
328 | return changed; |
329 | } |
330 | |
331 | static const struct snd_kcontrol_new rolloff_control = { |
332 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
333 | .name = "DAC Filter Playback Enum" , |
334 | .info = rolloff_info, |
335 | .get = rolloff_get, |
336 | .put = rolloff_put, |
337 | }; |
338 | |
339 | static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, |
340 | unsigned int reg, unsigned int mute) |
341 | { |
342 | if (reg == AC97_LINE) { |
343 | spin_lock_irq(lock: &chip->reg_lock); |
344 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, |
345 | value: mute ? GPIO_D1_INPUT_ROUTE : 0, |
346 | GPIO_D1_INPUT_ROUTE); |
347 | spin_unlock_irq(lock: &chip->reg_lock); |
348 | } |
349 | } |
350 | |
351 | static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); |
352 | |
353 | static int xonar_d1_mixer_init(struct oxygen *chip) |
354 | { |
355 | int err; |
356 | |
357 | err = snd_ctl_add(card: chip->card, kcontrol: snd_ctl_new1(kcontrolnew: &front_panel_switch, private_data: chip)); |
358 | if (err < 0) |
359 | return err; |
360 | err = snd_ctl_add(card: chip->card, kcontrol: snd_ctl_new1(kcontrolnew: &rolloff_control, private_data: chip)); |
361 | if (err < 0) |
362 | return err; |
363 | return 0; |
364 | } |
365 | |
366 | static void dump_cs4362a_registers(struct xonar_cs43xx *data, |
367 | struct snd_info_buffer *buffer) |
368 | { |
369 | unsigned int i; |
370 | |
371 | snd_iprintf(buffer, "\nCS4362A:" ); |
372 | for (i = 1; i <= 14; ++i) |
373 | snd_iprintf(buffer, " %02x" , data->cs4362a_regs[i]); |
374 | snd_iprintf(buffer, "\n" ); |
375 | } |
376 | |
377 | static void dump_d1_registers(struct oxygen *chip, |
378 | struct snd_info_buffer *buffer) |
379 | { |
380 | struct xonar_cs43xx *data = chip->model_data; |
381 | unsigned int i; |
382 | |
383 | snd_iprintf(buffer, "\nCS4398: 7?" ); |
384 | for (i = 2; i < 8; ++i) |
385 | snd_iprintf(buffer, " %02x" , data->cs4398_regs[i]); |
386 | snd_iprintf(buffer, "\n" ); |
387 | dump_cs4362a_registers(data, buffer); |
388 | } |
389 | |
390 | static const struct oxygen_model model_xonar_d1 = { |
391 | .longname = "Asus Virtuoso 100" , |
392 | .chip = "AV200" , |
393 | .init = xonar_d1_init, |
394 | .mixer_init = xonar_d1_mixer_init, |
395 | .cleanup = xonar_d1_cleanup, |
396 | .suspend = xonar_d1_suspend, |
397 | .resume = xonar_d1_resume, |
398 | .set_dac_params = set_cs43xx_params, |
399 | .set_adc_params = xonar_set_cs53x1_params, |
400 | .update_dac_volume = update_cs43xx_volume, |
401 | .update_dac_mute = update_cs43xx_mute, |
402 | .update_center_lfe_mix = update_cs43xx_center_lfe_mix, |
403 | .ac97_switch = xonar_d1_line_mic_ac97_switch, |
404 | .dump_registers = dump_d1_registers, |
405 | .dac_tlv = cs4362a_db_scale, |
406 | .model_data_size = sizeof(struct xonar_cs43xx), |
407 | .device_config = PLAYBACK_0_TO_I2S | |
408 | PLAYBACK_1_TO_SPDIF | |
409 | CAPTURE_0_FROM_I2S_2 | |
410 | CAPTURE_1_FROM_SPDIF | |
411 | AC97_FMIC_SWITCH, |
412 | .dac_channels_pcm = 8, |
413 | .dac_channels_mixer = 8, |
414 | .dac_volume_min = 127 - 60, |
415 | .dac_volume_max = 127, |
416 | .function_flags = OXYGEN_FUNCTION_2WIRE, |
417 | .dac_mclks = OXYGEN_MCLKS(256, 128, 128), |
418 | .adc_mclks = OXYGEN_MCLKS(256, 128, 128), |
419 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
420 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
421 | }; |
422 | |
423 | int get_xonar_cs43xx_model(struct oxygen *chip, |
424 | const struct pci_device_id *id) |
425 | { |
426 | switch (id->subdevice) { |
427 | case 0x834f: |
428 | chip->model = model_xonar_d1; |
429 | chip->model.shortname = "Xonar D1" ; |
430 | break; |
431 | case 0x8275: |
432 | case 0x8327: |
433 | chip->model = model_xonar_d1; |
434 | chip->model.shortname = "Xonar DX" ; |
435 | chip->model.init = xonar_dx_init; |
436 | break; |
437 | default: |
438 | return -EINVAL; |
439 | } |
440 | return 0; |
441 | } |
442 | |