diff options
Diffstat (limited to 'sound/pci/oxygen/xonar_pcm179x.c')
-rw-r--r-- | sound/pci/oxygen/xonar_pcm179x.c | 1115 |
1 files changed, 1115 insertions, 0 deletions
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c new file mode 100644 index 000000000000..ba18fb546b4f --- /dev/null +++ b/sound/pci/oxygen/xonar_pcm179x.c | |||
@@ -0,0 +1,1115 @@ | |||
1 | /* | ||
2 | * card driver for models with PCM1796 DACs (Xonar D2/D2X/HDAV1.3/ST/STX) | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
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 | /* | ||
20 | * Xonar D2/D2X | ||
21 | * ------------ | ||
22 | * | ||
23 | * CMI8788: | ||
24 | * | ||
25 | * SPI 0 -> 1st PCM1796 (front) | ||
26 | * SPI 1 -> 2nd PCM1796 (surround) | ||
27 | * SPI 2 -> 3rd PCM1796 (center/LFE) | ||
28 | * SPI 4 -> 4th PCM1796 (back) | ||
29 | * | ||
30 | * GPIO 2 -> M0 of CS5381 | ||
31 | * GPIO 3 -> M1 of CS5381 | ||
32 | * GPIO 5 <- external power present (D2X only) | ||
33 | * GPIO 7 -> ALT | ||
34 | * GPIO 8 -> enable output to speakers | ||
35 | * | ||
36 | * CM9780: | ||
37 | * | ||
38 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | ||
39 | */ | ||
40 | |||
41 | /* | ||
42 | * Xonar HDAV1.3 (Deluxe) | ||
43 | * ---------------------- | ||
44 | * | ||
45 | * CMI8788: | ||
46 | * | ||
47 | * I²C <-> PCM1796 (front) | ||
48 | * | ||
49 | * GPI 0 <- external power present | ||
50 | * | ||
51 | * GPIO 0 -> enable output to speakers | ||
52 | * GPIO 2 -> M0 of CS5381 | ||
53 | * GPIO 3 -> M1 of CS5381 | ||
54 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
55 | * | ||
56 | * TXD -> HDMI controller | ||
57 | * RXD <- HDMI controller | ||
58 | * | ||
59 | * PCM1796 front: AD1,0 <- 0,0 | ||
60 | * | ||
61 | * CM9780: | ||
62 | * | ||
63 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | ||
64 | * | ||
65 | * no daughterboard | ||
66 | * ---------------- | ||
67 | * | ||
68 | * GPIO 4 <- 1 | ||
69 | * | ||
70 | * H6 daughterboard | ||
71 | * ---------------- | ||
72 | * | ||
73 | * GPIO 4 <- 0 | ||
74 | * GPIO 5 <- 0 | ||
75 | * | ||
76 | * I²C <-> PCM1796 (surround) | ||
77 | * <-> PCM1796 (center/LFE) | ||
78 | * <-> PCM1796 (back) | ||
79 | * | ||
80 | * PCM1796 surround: AD1,0 <- 0,1 | ||
81 | * PCM1796 center/LFE: AD1,0 <- 1,0 | ||
82 | * PCM1796 back: AD1,0 <- 1,1 | ||
83 | * | ||
84 | * unknown daughterboard | ||
85 | * --------------------- | ||
86 | * | ||
87 | * GPIO 4 <- 0 | ||
88 | * GPIO 5 <- 1 | ||
89 | * | ||
90 | * I²C <-> CS4362A (surround, center/LFE, back) | ||
91 | * | ||
92 | * CS4362A: AD0 <- 0 | ||
93 | */ | ||
94 | |||
95 | /* | ||
96 | * Xonar Essence ST (Deluxe)/STX | ||
97 | * ----------------------------- | ||
98 | * | ||
99 | * CMI8788: | ||
100 | * | ||
101 | * I²C <-> PCM1792A | ||
102 | * <-> CS2000 (ST only) | ||
103 | * | ||
104 | * ADC1 MCLK -> REF_CLK of CS2000 (ST only) | ||
105 | * | ||
106 | * GPI 0 <- external power present (STX only) | ||
107 | * | ||
108 | * GPIO 0 -> enable output to speakers | ||
109 | * GPIO 1 -> route HP to front panel (0) or rear jack (1) | ||
110 | * GPIO 2 -> M0 of CS5381 | ||
111 | * GPIO 3 -> M1 of CS5381 | ||
112 | * GPIO 7 -> route output to speaker jacks (0) or HP (1) | ||
113 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
114 | * | ||
115 | * PCM1792A: | ||
116 | * | ||
117 | * AD1,0 <- 0,0 | ||
118 | * SCK <- CLK_OUT of CS2000 (ST only) | ||
119 | * | ||
120 | * CS2000: | ||
121 | * | ||
122 | * AD0 <- 0 | ||
123 | * | ||
124 | * CM9780: | ||
125 | * | ||
126 | * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input | ||
127 | * | ||
128 | * H6 daughterboard | ||
129 | * ---------------- | ||
130 | * | ||
131 | * GPIO 4 <- 0 | ||
132 | * GPIO 5 <- 0 | ||
133 | */ | ||
134 | |||
135 | #include <linux/pci.h> | ||
136 | #include <linux/delay.h> | ||
137 | #include <linux/mutex.h> | ||
138 | #include <sound/ac97_codec.h> | ||
139 | #include <sound/control.h> | ||
140 | #include <sound/core.h> | ||
141 | #include <sound/pcm.h> | ||
142 | #include <sound/pcm_params.h> | ||
143 | #include <sound/tlv.h> | ||
144 | #include "xonar.h" | ||
145 | #include "cm9780.h" | ||
146 | #include "pcm1796.h" | ||
147 | #include "cs2000.h" | ||
148 | |||
149 | |||
150 | #define GPIO_D2X_EXT_POWER 0x0020 | ||
151 | #define GPIO_D2_ALT 0x0080 | ||
152 | #define GPIO_D2_OUTPUT_ENABLE 0x0100 | ||
153 | |||
154 | #define GPI_EXT_POWER 0x01 | ||
155 | #define GPIO_INPUT_ROUTE 0x0100 | ||
156 | |||
157 | #define GPIO_HDAV_OUTPUT_ENABLE 0x0001 | ||
158 | |||
159 | #define GPIO_DB_MASK 0x0030 | ||
160 | #define GPIO_DB_H6 0x0000 | ||
161 | |||
162 | #define GPIO_ST_OUTPUT_ENABLE 0x0001 | ||
163 | #define GPIO_ST_HP_REAR 0x0002 | ||
164 | #define GPIO_ST_HP 0x0080 | ||
165 | |||
166 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ | ||
167 | #define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /W=0 */ | ||
168 | |||
169 | #define PCM1796_REG_BASE 16 | ||
170 | |||
171 | |||
172 | struct xonar_pcm179x { | ||
173 | struct xonar_generic generic; | ||
174 | unsigned int dacs; | ||
175 | u8 pcm1796_regs[4][5]; | ||
176 | unsigned int current_rate; | ||
177 | bool os_128; | ||
178 | bool hp_active; | ||
179 | s8 hp_gain_offset; | ||
180 | bool has_cs2000; | ||
181 | u8 cs2000_fun_cfg_1; | ||
182 | }; | ||
183 | |||
184 | struct xonar_hdav { | ||
185 | struct xonar_pcm179x pcm179x; | ||
186 | struct xonar_hdmi hdmi; | ||
187 | }; | ||
188 | |||
189 | |||
190 | static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec, | ||
191 | u8 reg, u8 value) | ||
192 | { | ||
193 | /* maps ALSA channel pair number to SPI output */ | ||
194 | static const u8 codec_map[4] = { | ||
195 | 0, 1, 2, 4 | ||
196 | }; | ||
197 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
198 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
199 | OXYGEN_SPI_CLOCK_160 | | ||
200 | (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) | | ||
201 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
202 | (reg << 8) | value); | ||
203 | } | ||
204 | |||
205 | static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec, | ||
206 | u8 reg, u8 value) | ||
207 | { | ||
208 | oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value); | ||
209 | } | ||
210 | |||
211 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, | ||
212 | u8 reg, u8 value) | ||
213 | { | ||
214 | struct xonar_pcm179x *data = chip->model_data; | ||
215 | |||
216 | if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) == | ||
217 | OXYGEN_FUNCTION_SPI) | ||
218 | pcm1796_write_spi(chip, codec, reg, value); | ||
219 | else | ||
220 | pcm1796_write_i2c(chip, codec, reg, value); | ||
221 | if ((unsigned int)(reg - PCM1796_REG_BASE) | ||
222 | < ARRAY_SIZE(data->pcm1796_regs[codec])) | ||
223 | data->pcm1796_regs[codec][reg - PCM1796_REG_BASE] = value; | ||
224 | } | ||
225 | |||
226 | static void pcm1796_write_cached(struct oxygen *chip, unsigned int codec, | ||
227 | u8 reg, u8 value) | ||
228 | { | ||
229 | struct xonar_pcm179x *data = chip->model_data; | ||
230 | |||
231 | if (value != data->pcm1796_regs[codec][reg - PCM1796_REG_BASE]) | ||
232 | pcm1796_write(chip, codec, reg, value); | ||
233 | } | ||
234 | |||
235 | static void cs2000_write(struct oxygen *chip, u8 reg, u8 value) | ||
236 | { | ||
237 | struct xonar_pcm179x *data = chip->model_data; | ||
238 | |||
239 | oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); | ||
240 | if (reg == CS2000_FUN_CFG_1) | ||
241 | data->cs2000_fun_cfg_1 = value; | ||
242 | } | ||
243 | |||
244 | static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value) | ||
245 | { | ||
246 | struct xonar_pcm179x *data = chip->model_data; | ||
247 | |||
248 | if (reg != CS2000_FUN_CFG_1 || | ||
249 | value != data->cs2000_fun_cfg_1) | ||
250 | cs2000_write(chip, reg, value); | ||
251 | } | ||
252 | |||
253 | static void pcm1796_registers_init(struct oxygen *chip) | ||
254 | { | ||
255 | struct xonar_pcm179x *data = chip->model_data; | ||
256 | unsigned int i; | ||
257 | s8 gain_offset; | ||
258 | |||
259 | gain_offset = data->hp_active ? data->hp_gain_offset : 0; | ||
260 | for (i = 0; i < data->dacs; ++i) { | ||
261 | /* set ATLD before ATL/ATR */ | ||
262 | pcm1796_write(chip, i, 18, | ||
263 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE]); | ||
264 | pcm1796_write(chip, i, 16, chip->dac_volume[i * 2] | ||
265 | + gain_offset); | ||
266 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1] | ||
267 | + gain_offset); | ||
268 | pcm1796_write(chip, i, 19, | ||
269 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE]); | ||
270 | pcm1796_write(chip, i, 20, | ||
271 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); | ||
272 | pcm1796_write(chip, i, 21, 0); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | static void pcm1796_init(struct oxygen *chip) | ||
277 | { | ||
278 | struct xonar_pcm179x *data = chip->model_data; | ||
279 | |||
280 | data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | | ||
281 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | ||
282 | data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = | ||
283 | PCM1796_FLT_SHARP | PCM1796_ATS_1; | ||
284 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; | ||
285 | pcm1796_registers_init(chip); | ||
286 | data->current_rate = 48000; | ||
287 | } | ||
288 | |||
289 | static void xonar_d2_init(struct oxygen *chip) | ||
290 | { | ||
291 | struct xonar_pcm179x *data = chip->model_data; | ||
292 | |||
293 | data->generic.anti_pop_delay = 300; | ||
294 | data->generic.output_enable_bit = GPIO_D2_OUTPUT_ENABLE; | ||
295 | data->dacs = 4; | ||
296 | |||
297 | pcm1796_init(chip); | ||
298 | |||
299 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT); | ||
300 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT); | ||
301 | |||
302 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); | ||
303 | |||
304 | xonar_init_cs53x1(chip); | ||
305 | xonar_enable_output(chip); | ||
306 | |||
307 | snd_component_add(chip->card, "PCM1796"); | ||
308 | snd_component_add(chip->card, "CS5381"); | ||
309 | } | ||
310 | |||
311 | static void xonar_d2x_init(struct oxygen *chip) | ||
312 | { | ||
313 | struct xonar_pcm179x *data = chip->model_data; | ||
314 | |||
315 | data->generic.ext_power_reg = OXYGEN_GPIO_DATA; | ||
316 | data->generic.ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; | ||
317 | data->generic.ext_power_bit = GPIO_D2X_EXT_POWER; | ||
318 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER); | ||
319 | xonar_init_ext_power(chip); | ||
320 | xonar_d2_init(chip); | ||
321 | } | ||
322 | |||
323 | static void xonar_hdav_init(struct oxygen *chip) | ||
324 | { | ||
325 | struct xonar_hdav *data = chip->model_data; | ||
326 | |||
327 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
328 | OXYGEN_2WIRE_LENGTH_8 | | ||
329 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
330 | OXYGEN_2WIRE_SPEED_FAST); | ||
331 | |||
332 | data->pcm179x.generic.anti_pop_delay = 100; | ||
333 | data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE; | ||
334 | data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA; | ||
335 | data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
336 | data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER; | ||
337 | data->pcm179x.dacs = chip->model.private_data ? 4 : 1; | ||
338 | |||
339 | pcm1796_init(chip); | ||
340 | |||
341 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE); | ||
342 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE); | ||
343 | |||
344 | xonar_init_cs53x1(chip); | ||
345 | xonar_init_ext_power(chip); | ||
346 | xonar_hdmi_init(chip, &data->hdmi); | ||
347 | xonar_enable_output(chip); | ||
348 | |||
349 | snd_component_add(chip->card, "PCM1796"); | ||
350 | snd_component_add(chip->card, "CS5381"); | ||
351 | } | ||
352 | |||
353 | static void xonar_st_init_i2c(struct oxygen *chip) | ||
354 | { | ||
355 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
356 | OXYGEN_2WIRE_LENGTH_8 | | ||
357 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
358 | OXYGEN_2WIRE_SPEED_FAST); | ||
359 | } | ||
360 | |||
361 | static void xonar_st_init_common(struct oxygen *chip) | ||
362 | { | ||
363 | struct xonar_pcm179x *data = chip->model_data; | ||
364 | |||
365 | data->generic.anti_pop_delay = 100; | ||
366 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; | ||
367 | data->dacs = chip->model.private_data ? 4 : 1; | ||
368 | data->hp_gain_offset = 2*-18; | ||
369 | |||
370 | pcm1796_init(chip); | ||
371 | |||
372 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
373 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); | ||
374 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, | ||
375 | GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); | ||
376 | |||
377 | xonar_init_cs53x1(chip); | ||
378 | xonar_enable_output(chip); | ||
379 | |||
380 | snd_component_add(chip->card, "PCM1792A"); | ||
381 | snd_component_add(chip->card, "CS5381"); | ||
382 | } | ||
383 | |||
384 | static void cs2000_registers_init(struct oxygen *chip) | ||
385 | { | ||
386 | struct xonar_pcm179x *data = chip->model_data; | ||
387 | |||
388 | cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_FREEZE); | ||
389 | cs2000_write(chip, CS2000_DEV_CTRL, 0); | ||
390 | cs2000_write(chip, CS2000_DEV_CFG_1, | ||
391 | CS2000_R_MOD_SEL_1 | | ||
392 | (0 << CS2000_R_SEL_SHIFT) | | ||
393 | CS2000_AUX_OUT_SRC_REF_CLK | | ||
394 | CS2000_EN_DEV_CFG_1); | ||
395 | cs2000_write(chip, CS2000_DEV_CFG_2, | ||
396 | (0 << CS2000_LOCK_CLK_SHIFT) | | ||
397 | CS2000_FRAC_N_SRC_STATIC); | ||
398 | cs2000_write(chip, CS2000_RATIO_0 + 0, 0x00); /* 1.0 */ | ||
399 | cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10); | ||
400 | cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00); | ||
401 | cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00); | ||
402 | cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1); | ||
403 | cs2000_write(chip, CS2000_FUN_CFG_2, 0); | ||
404 | cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2); | ||
405 | } | ||
406 | |||
407 | static void xonar_st_init(struct oxygen *chip) | ||
408 | { | ||
409 | struct xonar_pcm179x *data = chip->model_data; | ||
410 | |||
411 | data->has_cs2000 = 1; | ||
412 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; | ||
413 | |||
414 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | ||
415 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S | | ||
416 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
417 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
418 | |||
419 | xonar_st_init_i2c(chip); | ||
420 | cs2000_registers_init(chip); | ||
421 | xonar_st_init_common(chip); | ||
422 | |||
423 | snd_component_add(chip->card, "CS2000"); | ||
424 | } | ||
425 | |||
426 | static void xonar_stx_init(struct oxygen *chip) | ||
427 | { | ||
428 | struct xonar_pcm179x *data = chip->model_data; | ||
429 | |||
430 | xonar_st_init_i2c(chip); | ||
431 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; | ||
432 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
433 | data->generic.ext_power_bit = GPI_EXT_POWER; | ||
434 | xonar_init_ext_power(chip); | ||
435 | xonar_st_init_common(chip); | ||
436 | } | ||
437 | |||
438 | static void xonar_d2_cleanup(struct oxygen *chip) | ||
439 | { | ||
440 | xonar_disable_output(chip); | ||
441 | } | ||
442 | |||
443 | static void xonar_hdav_cleanup(struct oxygen *chip) | ||
444 | { | ||
445 | xonar_hdmi_cleanup(chip); | ||
446 | xonar_disable_output(chip); | ||
447 | msleep(2); | ||
448 | } | ||
449 | |||
450 | static void xonar_st_cleanup(struct oxygen *chip) | ||
451 | { | ||
452 | xonar_disable_output(chip); | ||
453 | } | ||
454 | |||
455 | static void xonar_d2_suspend(struct oxygen *chip) | ||
456 | { | ||
457 | xonar_d2_cleanup(chip); | ||
458 | } | ||
459 | |||
460 | static void xonar_hdav_suspend(struct oxygen *chip) | ||
461 | { | ||
462 | xonar_hdav_cleanup(chip); | ||
463 | } | ||
464 | |||
465 | static void xonar_st_suspend(struct oxygen *chip) | ||
466 | { | ||
467 | xonar_st_cleanup(chip); | ||
468 | } | ||
469 | |||
470 | static void xonar_d2_resume(struct oxygen *chip) | ||
471 | { | ||
472 | pcm1796_registers_init(chip); | ||
473 | xonar_enable_output(chip); | ||
474 | } | ||
475 | |||
476 | static void xonar_hdav_resume(struct oxygen *chip) | ||
477 | { | ||
478 | struct xonar_hdav *data = chip->model_data; | ||
479 | |||
480 | pcm1796_registers_init(chip); | ||
481 | xonar_hdmi_resume(chip, &data->hdmi); | ||
482 | xonar_enable_output(chip); | ||
483 | } | ||
484 | |||
485 | static void xonar_stx_resume(struct oxygen *chip) | ||
486 | { | ||
487 | pcm1796_registers_init(chip); | ||
488 | xonar_enable_output(chip); | ||
489 | } | ||
490 | |||
491 | static void xonar_st_resume(struct oxygen *chip) | ||
492 | { | ||
493 | cs2000_registers_init(chip); | ||
494 | xonar_stx_resume(chip); | ||
495 | } | ||
496 | |||
497 | static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate) | ||
498 | { | ||
499 | struct xonar_pcm179x *data = chip->model_data; | ||
500 | |||
501 | if (rate <= 32000) | ||
502 | return OXYGEN_I2S_MCLK_512; | ||
503 | else if (rate <= 48000 && data->os_128) | ||
504 | return OXYGEN_I2S_MCLK_512; | ||
505 | else if (rate <= 96000) | ||
506 | return OXYGEN_I2S_MCLK_256; | ||
507 | else | ||
508 | return OXYGEN_I2S_MCLK_128; | ||
509 | } | ||
510 | |||
511 | static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip, | ||
512 | unsigned int channel, | ||
513 | struct snd_pcm_hw_params *params) | ||
514 | { | ||
515 | if (channel == PCM_MULTICH) | ||
516 | return mclk_from_rate(chip, params_rate(params)); | ||
517 | else | ||
518 | return oxygen_default_i2s_mclk(chip, channel, params); | ||
519 | } | ||
520 | |||
521 | static void update_pcm1796_oversampling(struct oxygen *chip) | ||
522 | { | ||
523 | struct xonar_pcm179x *data = chip->model_data; | ||
524 | unsigned int i; | ||
525 | u8 reg; | ||
526 | |||
527 | if (data->current_rate <= 32000) | ||
528 | reg = PCM1796_OS_128; | ||
529 | else if (data->current_rate <= 48000 && data->os_128) | ||
530 | reg = PCM1796_OS_128; | ||
531 | else if (data->current_rate <= 96000 || data->os_128) | ||
532 | reg = PCM1796_OS_64; | ||
533 | else | ||
534 | reg = PCM1796_OS_32; | ||
535 | for (i = 0; i < data->dacs; ++i) | ||
536 | pcm1796_write_cached(chip, i, 20, reg); | ||
537 | } | ||
538 | |||
539 | static void set_pcm1796_params(struct oxygen *chip, | ||
540 | struct snd_pcm_hw_params *params) | ||
541 | { | ||
542 | struct xonar_pcm179x *data = chip->model_data; | ||
543 | |||
544 | data->current_rate = params_rate(params); | ||
545 | update_pcm1796_oversampling(chip); | ||
546 | } | ||
547 | |||
548 | static void update_pcm1796_volume(struct oxygen *chip) | ||
549 | { | ||
550 | struct xonar_pcm179x *data = chip->model_data; | ||
551 | unsigned int i; | ||
552 | s8 gain_offset; | ||
553 | |||
554 | gain_offset = data->hp_active ? data->hp_gain_offset : 0; | ||
555 | for (i = 0; i < data->dacs; ++i) { | ||
556 | pcm1796_write_cached(chip, i, 16, chip->dac_volume[i * 2] | ||
557 | + gain_offset); | ||
558 | pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1] | ||
559 | + gain_offset); | ||
560 | } | ||
561 | } | ||
562 | |||
563 | static void update_pcm1796_mute(struct oxygen *chip) | ||
564 | { | ||
565 | struct xonar_pcm179x *data = chip->model_data; | ||
566 | unsigned int i; | ||
567 | u8 value; | ||
568 | |||
569 | value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | ||
570 | if (chip->dac_mute) | ||
571 | value |= PCM1796_MUTE; | ||
572 | for (i = 0; i < data->dacs; ++i) | ||
573 | pcm1796_write_cached(chip, i, 18, value); | ||
574 | } | ||
575 | |||
576 | static void update_cs2000_rate(struct oxygen *chip, unsigned int rate) | ||
577 | { | ||
578 | struct xonar_pcm179x *data = chip->model_data; | ||
579 | u8 rate_mclk, reg; | ||
580 | |||
581 | switch (rate) { | ||
582 | /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */ | ||
583 | case 32000: | ||
584 | rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; | ||
585 | break; | ||
586 | case 44100: | ||
587 | if (data->os_128) | ||
588 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
589 | else | ||
590 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128; | ||
591 | break; | ||
592 | default: /* 48000 */ | ||
593 | if (data->os_128) | ||
594 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
595 | else | ||
596 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128; | ||
597 | break; | ||
598 | case 64000: | ||
599 | rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; | ||
600 | break; | ||
601 | case 88200: | ||
602 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
603 | break; | ||
604 | case 96000: | ||
605 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
606 | break; | ||
607 | case 176400: | ||
608 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
609 | break; | ||
610 | case 192000: | ||
611 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
612 | break; | ||
613 | } | ||
614 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, | ||
615 | OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); | ||
616 | if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) | ||
617 | reg = CS2000_REF_CLK_DIV_1; | ||
618 | else | ||
619 | reg = CS2000_REF_CLK_DIV_2; | ||
620 | cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg); | ||
621 | } | ||
622 | |||
623 | static void set_st_params(struct oxygen *chip, | ||
624 | struct snd_pcm_hw_params *params) | ||
625 | { | ||
626 | update_cs2000_rate(chip, params_rate(params)); | ||
627 | set_pcm1796_params(chip, params); | ||
628 | } | ||
629 | |||
630 | static void set_hdav_params(struct oxygen *chip, | ||
631 | struct snd_pcm_hw_params *params) | ||
632 | { | ||
633 | struct xonar_hdav *data = chip->model_data; | ||
634 | |||
635 | set_pcm1796_params(chip, params); | ||
636 | xonar_set_hdmi_params(chip, &data->hdmi, params); | ||
637 | } | ||
638 | |||
639 | static const struct snd_kcontrol_new alt_switch = { | ||
640 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
641 | .name = "Analog Loopback Switch", | ||
642 | .info = snd_ctl_boolean_mono_info, | ||
643 | .get = xonar_gpio_bit_switch_get, | ||
644 | .put = xonar_gpio_bit_switch_put, | ||
645 | .private_value = GPIO_D2_ALT, | ||
646 | }; | ||
647 | |||
648 | static int rolloff_info(struct snd_kcontrol *ctl, | ||
649 | struct snd_ctl_elem_info *info) | ||
650 | { | ||
651 | static const char *const names[2] = { | ||
652 | "Sharp Roll-off", "Slow Roll-off" | ||
653 | }; | ||
654 | |||
655 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
656 | info->count = 1; | ||
657 | info->value.enumerated.items = 2; | ||
658 | if (info->value.enumerated.item >= 2) | ||
659 | info->value.enumerated.item = 1; | ||
660 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static int rolloff_get(struct snd_kcontrol *ctl, | ||
665 | struct snd_ctl_elem_value *value) | ||
666 | { | ||
667 | struct oxygen *chip = ctl->private_data; | ||
668 | struct xonar_pcm179x *data = chip->model_data; | ||
669 | |||
670 | value->value.enumerated.item[0] = | ||
671 | (data->pcm1796_regs[0][19 - PCM1796_REG_BASE] & | ||
672 | PCM1796_FLT_MASK) != PCM1796_FLT_SHARP; | ||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static int rolloff_put(struct snd_kcontrol *ctl, | ||
677 | struct snd_ctl_elem_value *value) | ||
678 | { | ||
679 | struct oxygen *chip = ctl->private_data; | ||
680 | struct xonar_pcm179x *data = chip->model_data; | ||
681 | unsigned int i; | ||
682 | int changed; | ||
683 | u8 reg; | ||
684 | |||
685 | mutex_lock(&chip->mutex); | ||
686 | reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE]; | ||
687 | reg &= ~PCM1796_FLT_MASK; | ||
688 | if (!value->value.enumerated.item[0]) | ||
689 | reg |= PCM1796_FLT_SHARP; | ||
690 | else | ||
691 | reg |= PCM1796_FLT_SLOW; | ||
692 | changed = reg != data->pcm1796_regs[0][19 - PCM1796_REG_BASE]; | ||
693 | if (changed) { | ||
694 | for (i = 0; i < data->dacs; ++i) | ||
695 | pcm1796_write(chip, i, 19, reg); | ||
696 | } | ||
697 | mutex_unlock(&chip->mutex); | ||
698 | return changed; | ||
699 | } | ||
700 | |||
701 | static const struct snd_kcontrol_new rolloff_control = { | ||
702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
703 | .name = "DAC Filter Playback Enum", | ||
704 | .info = rolloff_info, | ||
705 | .get = rolloff_get, | ||
706 | .put = rolloff_put, | ||
707 | }; | ||
708 | |||
709 | static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
710 | { | ||
711 | static const char *const names[2] = { "64x", "128x" }; | ||
712 | |||
713 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
714 | info->count = 1; | ||
715 | info->value.enumerated.items = 2; | ||
716 | if (info->value.enumerated.item >= 2) | ||
717 | info->value.enumerated.item = 1; | ||
718 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static int os_128_get(struct snd_kcontrol *ctl, | ||
723 | struct snd_ctl_elem_value *value) | ||
724 | { | ||
725 | struct oxygen *chip = ctl->private_data; | ||
726 | struct xonar_pcm179x *data = chip->model_data; | ||
727 | |||
728 | value->value.enumerated.item[0] = data->os_128; | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int os_128_put(struct snd_kcontrol *ctl, | ||
733 | struct snd_ctl_elem_value *value) | ||
734 | { | ||
735 | struct oxygen *chip = ctl->private_data; | ||
736 | struct xonar_pcm179x *data = chip->model_data; | ||
737 | int changed; | ||
738 | |||
739 | mutex_lock(&chip->mutex); | ||
740 | changed = value->value.enumerated.item[0] != data->os_128; | ||
741 | if (changed) { | ||
742 | data->os_128 = value->value.enumerated.item[0]; | ||
743 | if (data->has_cs2000) | ||
744 | update_cs2000_rate(chip, data->current_rate); | ||
745 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, | ||
746 | mclk_from_rate(chip, data->current_rate), | ||
747 | OXYGEN_I2S_MCLK_MASK); | ||
748 | update_pcm1796_oversampling(chip); | ||
749 | } | ||
750 | mutex_unlock(&chip->mutex); | ||
751 | return changed; | ||
752 | } | ||
753 | |||
754 | static const struct snd_kcontrol_new os_128_control = { | ||
755 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
756 | .name = "DAC Oversampling Playback Enum", | ||
757 | .info = os_128_info, | ||
758 | .get = os_128_get, | ||
759 | .put = os_128_put, | ||
760 | }; | ||
761 | |||
762 | static int st_output_switch_info(struct snd_kcontrol *ctl, | ||
763 | struct snd_ctl_elem_info *info) | ||
764 | { | ||
765 | static const char *const names[3] = { | ||
766 | "Speakers", "Headphones", "FP Headphones" | ||
767 | }; | ||
768 | |||
769 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
770 | info->count = 1; | ||
771 | info->value.enumerated.items = 3; | ||
772 | if (info->value.enumerated.item >= 3) | ||
773 | info->value.enumerated.item = 2; | ||
774 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
775 | return 0; | ||
776 | } | ||
777 | |||
778 | static int st_output_switch_get(struct snd_kcontrol *ctl, | ||
779 | struct snd_ctl_elem_value *value) | ||
780 | { | ||
781 | struct oxygen *chip = ctl->private_data; | ||
782 | u16 gpio; | ||
783 | |||
784 | gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
785 | if (!(gpio & GPIO_ST_HP)) | ||
786 | value->value.enumerated.item[0] = 0; | ||
787 | else if (gpio & GPIO_ST_HP_REAR) | ||
788 | value->value.enumerated.item[0] = 1; | ||
789 | else | ||
790 | value->value.enumerated.item[0] = 2; | ||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | |||
795 | static int st_output_switch_put(struct snd_kcontrol *ctl, | ||
796 | struct snd_ctl_elem_value *value) | ||
797 | { | ||
798 | struct oxygen *chip = ctl->private_data; | ||
799 | struct xonar_pcm179x *data = chip->model_data; | ||
800 | u16 gpio_old, gpio; | ||
801 | |||
802 | mutex_lock(&chip->mutex); | ||
803 | gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
804 | gpio = gpio_old; | ||
805 | switch (value->value.enumerated.item[0]) { | ||
806 | case 0: | ||
807 | gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR); | ||
808 | break; | ||
809 | case 1: | ||
810 | gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR; | ||
811 | break; | ||
812 | case 2: | ||
813 | gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR; | ||
814 | break; | ||
815 | } | ||
816 | oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio); | ||
817 | data->hp_active = gpio & GPIO_ST_HP; | ||
818 | update_pcm1796_volume(chip); | ||
819 | mutex_unlock(&chip->mutex); | ||
820 | return gpio != gpio_old; | ||
821 | } | ||
822 | |||
823 | static int st_hp_volume_offset_info(struct snd_kcontrol *ctl, | ||
824 | struct snd_ctl_elem_info *info) | ||
825 | { | ||
826 | static const char *const names[3] = { | ||
827 | "< 64 ohms", "64-300 ohms", "300-600 ohms" | ||
828 | }; | ||
829 | |||
830 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
831 | info->count = 1; | ||
832 | info->value.enumerated.items = 3; | ||
833 | if (info->value.enumerated.item > 2) | ||
834 | info->value.enumerated.item = 2; | ||
835 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, | ||
840 | struct snd_ctl_elem_value *value) | ||
841 | { | ||
842 | struct oxygen *chip = ctl->private_data; | ||
843 | struct xonar_pcm179x *data = chip->model_data; | ||
844 | |||
845 | mutex_lock(&chip->mutex); | ||
846 | if (data->hp_gain_offset < 2*-6) | ||
847 | value->value.enumerated.item[0] = 0; | ||
848 | else if (data->hp_gain_offset < 0) | ||
849 | value->value.enumerated.item[0] = 1; | ||
850 | else | ||
851 | value->value.enumerated.item[0] = 2; | ||
852 | mutex_unlock(&chip->mutex); | ||
853 | return 0; | ||
854 | } | ||
855 | |||
856 | |||
857 | static int st_hp_volume_offset_put(struct snd_kcontrol *ctl, | ||
858 | struct snd_ctl_elem_value *value) | ||
859 | { | ||
860 | static const s8 offsets[] = { 2*-18, 2*-6, 0 }; | ||
861 | struct oxygen *chip = ctl->private_data; | ||
862 | struct xonar_pcm179x *data = chip->model_data; | ||
863 | s8 offset; | ||
864 | int changed; | ||
865 | |||
866 | if (value->value.enumerated.item[0] > 2) | ||
867 | return -EINVAL; | ||
868 | offset = offsets[value->value.enumerated.item[0]]; | ||
869 | mutex_lock(&chip->mutex); | ||
870 | changed = offset != data->hp_gain_offset; | ||
871 | if (changed) { | ||
872 | data->hp_gain_offset = offset; | ||
873 | update_pcm1796_volume(chip); | ||
874 | } | ||
875 | mutex_unlock(&chip->mutex); | ||
876 | return changed; | ||
877 | } | ||
878 | |||
879 | static const struct snd_kcontrol_new st_controls[] = { | ||
880 | { | ||
881 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
882 | .name = "Analog Output", | ||
883 | .info = st_output_switch_info, | ||
884 | .get = st_output_switch_get, | ||
885 | .put = st_output_switch_put, | ||
886 | }, | ||
887 | { | ||
888 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
889 | .name = "Headphones Impedance Playback Enum", | ||
890 | .info = st_hp_volume_offset_info, | ||
891 | .get = st_hp_volume_offset_get, | ||
892 | .put = st_hp_volume_offset_put, | ||
893 | }, | ||
894 | }; | ||
895 | |||
896 | static void xonar_line_mic_ac97_switch(struct oxygen *chip, | ||
897 | unsigned int reg, unsigned int mute) | ||
898 | { | ||
899 | if (reg == AC97_LINE) { | ||
900 | spin_lock_irq(&chip->reg_lock); | ||
901 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
902 | mute ? GPIO_INPUT_ROUTE : 0, | ||
903 | GPIO_INPUT_ROUTE); | ||
904 | spin_unlock_irq(&chip->reg_lock); | ||
905 | } | ||
906 | } | ||
907 | |||
908 | static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0); | ||
909 | |||
910 | static int xonar_d2_control_filter(struct snd_kcontrol_new *template) | ||
911 | { | ||
912 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
913 | /* CD in is actually connected to the video in pin */ | ||
914 | template->private_value ^= AC97_CD ^ AC97_VIDEO; | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | static int xonar_st_control_filter(struct snd_kcontrol_new *template) | ||
919 | { | ||
920 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
921 | return 1; /* no CD input */ | ||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | static int add_pcm1796_controls(struct oxygen *chip) | ||
926 | { | ||
927 | int err; | ||
928 | |||
929 | err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); | ||
930 | if (err < 0) | ||
931 | return err; | ||
932 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | ||
933 | if (err < 0) | ||
934 | return err; | ||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | static int xonar_d2_mixer_init(struct oxygen *chip) | ||
939 | { | ||
940 | int err; | ||
941 | |||
942 | err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | ||
943 | if (err < 0) | ||
944 | return err; | ||
945 | err = add_pcm1796_controls(chip); | ||
946 | if (err < 0) | ||
947 | return err; | ||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static int xonar_hdav_mixer_init(struct oxygen *chip) | ||
952 | { | ||
953 | return add_pcm1796_controls(chip); | ||
954 | } | ||
955 | |||
956 | static int xonar_st_mixer_init(struct oxygen *chip) | ||
957 | { | ||
958 | unsigned int i; | ||
959 | int err; | ||
960 | |||
961 | for (i = 0; i < ARRAY_SIZE(st_controls); ++i) { | ||
962 | err = snd_ctl_add(chip->card, | ||
963 | snd_ctl_new1(&st_controls[i], chip)); | ||
964 | if (err < 0) | ||
965 | return err; | ||
966 | } | ||
967 | err = add_pcm1796_controls(chip); | ||
968 | if (err < 0) | ||
969 | return err; | ||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static const struct oxygen_model model_xonar_d2 = { | ||
974 | .longname = "Asus Virtuoso 200", | ||
975 | .chip = "AV200", | ||
976 | .init = xonar_d2_init, | ||
977 | .control_filter = xonar_d2_control_filter, | ||
978 | .mixer_init = xonar_d2_mixer_init, | ||
979 | .cleanup = xonar_d2_cleanup, | ||
980 | .suspend = xonar_d2_suspend, | ||
981 | .resume = xonar_d2_resume, | ||
982 | .get_i2s_mclk = get_pcm1796_i2s_mclk, | ||
983 | .set_dac_params = set_pcm1796_params, | ||
984 | .set_adc_params = xonar_set_cs53x1_params, | ||
985 | .update_dac_volume = update_pcm1796_volume, | ||
986 | .update_dac_mute = update_pcm1796_mute, | ||
987 | .dac_tlv = pcm1796_db_scale, | ||
988 | .model_data_size = sizeof(struct xonar_pcm179x), | ||
989 | .device_config = PLAYBACK_0_TO_I2S | | ||
990 | PLAYBACK_1_TO_SPDIF | | ||
991 | CAPTURE_0_FROM_I2S_2 | | ||
992 | CAPTURE_1_FROM_SPDIF | | ||
993 | MIDI_OUTPUT | | ||
994 | MIDI_INPUT, | ||
995 | .dac_channels = 8, | ||
996 | .dac_volume_min = 255 - 2*60, | ||
997 | .dac_volume_max = 255, | ||
998 | .misc_flags = OXYGEN_MISC_MIDI, | ||
999 | .function_flags = OXYGEN_FUNCTION_SPI | | ||
1000 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, | ||
1001 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1002 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1003 | }; | ||
1004 | |||
1005 | static const struct oxygen_model model_xonar_hdav = { | ||
1006 | .longname = "Asus Virtuoso 200", | ||
1007 | .chip = "AV200", | ||
1008 | .init = xonar_hdav_init, | ||
1009 | .mixer_init = xonar_hdav_mixer_init, | ||
1010 | .cleanup = xonar_hdav_cleanup, | ||
1011 | .suspend = xonar_hdav_suspend, | ||
1012 | .resume = xonar_hdav_resume, | ||
1013 | .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, | ||
1014 | .get_i2s_mclk = get_pcm1796_i2s_mclk, | ||
1015 | .set_dac_params = set_hdav_params, | ||
1016 | .set_adc_params = xonar_set_cs53x1_params, | ||
1017 | .update_dac_volume = update_pcm1796_volume, | ||
1018 | .update_dac_mute = update_pcm1796_mute, | ||
1019 | .uart_input = xonar_hdmi_uart_input, | ||
1020 | .ac97_switch = xonar_line_mic_ac97_switch, | ||
1021 | .dac_tlv = pcm1796_db_scale, | ||
1022 | .model_data_size = sizeof(struct xonar_hdav), | ||
1023 | .device_config = PLAYBACK_0_TO_I2S | | ||
1024 | PLAYBACK_1_TO_SPDIF | | ||
1025 | CAPTURE_0_FROM_I2S_2 | | ||
1026 | CAPTURE_1_FROM_SPDIF, | ||
1027 | .dac_channels = 8, | ||
1028 | .dac_volume_min = 255 - 2*60, | ||
1029 | .dac_volume_max = 255, | ||
1030 | .misc_flags = OXYGEN_MISC_MIDI, | ||
1031 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
1032 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1033 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1034 | }; | ||
1035 | |||
1036 | static const struct oxygen_model model_xonar_st = { | ||
1037 | .longname = "Asus Virtuoso 100", | ||
1038 | .chip = "AV200", | ||
1039 | .init = xonar_st_init, | ||
1040 | .control_filter = xonar_st_control_filter, | ||
1041 | .mixer_init = xonar_st_mixer_init, | ||
1042 | .cleanup = xonar_st_cleanup, | ||
1043 | .suspend = xonar_st_suspend, | ||
1044 | .resume = xonar_st_resume, | ||
1045 | .get_i2s_mclk = get_pcm1796_i2s_mclk, | ||
1046 | .set_dac_params = set_st_params, | ||
1047 | .set_adc_params = xonar_set_cs53x1_params, | ||
1048 | .update_dac_volume = update_pcm1796_volume, | ||
1049 | .update_dac_mute = update_pcm1796_mute, | ||
1050 | .ac97_switch = xonar_line_mic_ac97_switch, | ||
1051 | .dac_tlv = pcm1796_db_scale, | ||
1052 | .model_data_size = sizeof(struct xonar_pcm179x), | ||
1053 | .device_config = PLAYBACK_0_TO_I2S | | ||
1054 | PLAYBACK_1_TO_SPDIF | | ||
1055 | CAPTURE_0_FROM_I2S_2, | ||
1056 | .dac_channels = 2, | ||
1057 | .dac_volume_min = 255 - 2*60, | ||
1058 | .dac_volume_max = 255, | ||
1059 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
1060 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1061 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1062 | }; | ||
1063 | |||
1064 | int __devinit get_xonar_pcm179x_model(struct oxygen *chip, | ||
1065 | const struct pci_device_id *id) | ||
1066 | { | ||
1067 | switch (id->subdevice) { | ||
1068 | case 0x8269: | ||
1069 | chip->model = model_xonar_d2; | ||
1070 | chip->model.shortname = "Xonar D2"; | ||
1071 | break; | ||
1072 | case 0x82b7: | ||
1073 | chip->model = model_xonar_d2; | ||
1074 | chip->model.shortname = "Xonar D2X"; | ||
1075 | chip->model.init = xonar_d2x_init; | ||
1076 | break; | ||
1077 | case 0x8314: | ||
1078 | chip->model = model_xonar_hdav; | ||
1079 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); | ||
1080 | switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { | ||
1081 | default: | ||
1082 | chip->model.shortname = "Xonar HDAV1.3"; | ||
1083 | break; | ||
1084 | case GPIO_DB_H6: | ||
1085 | chip->model.shortname = "Xonar HDAV1.3+H6"; | ||
1086 | chip->model.private_data = 1; | ||
1087 | break; | ||
1088 | } | ||
1089 | break; | ||
1090 | case 0x835d: | ||
1091 | chip->model = model_xonar_st; | ||
1092 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); | ||
1093 | switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { | ||
1094 | default: | ||
1095 | chip->model.shortname = "Xonar ST"; | ||
1096 | break; | ||
1097 | case GPIO_DB_H6: | ||
1098 | chip->model.shortname = "Xonar ST+H6"; | ||
1099 | chip->model.dac_channels = 8; | ||
1100 | chip->model.private_data = 1; | ||
1101 | break; | ||
1102 | } | ||
1103 | break; | ||
1104 | case 0x835c: | ||
1105 | chip->model = model_xonar_st; | ||
1106 | chip->model.shortname = "Xonar STX"; | ||
1107 | chip->model.init = xonar_stx_init; | ||
1108 | chip->model.resume = xonar_stx_resume; | ||
1109 | chip->model.set_dac_params = set_pcm1796_params; | ||
1110 | break; | ||
1111 | default: | ||
1112 | return -EINVAL; | ||
1113 | } | ||
1114 | return 0; | ||
1115 | } | ||