diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2009-09-28 05:15:01 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-09-28 05:53:51 -0400 |
commit | 268304f4c4f0b8677d67400f04ad4e0271ec3742 (patch) | |
tree | 145c5e09c01962e8a228174ca52b9a95d723aac4 /sound | |
parent | 65c3ac885ce9852852b895a4a62212f62cb5f2e9 (diff) |
sound: virtuoso: fix Xonar Essence ST support
The Essence ST uses the CS2000 chip to generate the DAC master clock, so
we better initialize and program it appropriately.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/oxygen/cs2000.h | 83 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_pcm179x.c | 113 |
2 files changed, 190 insertions, 6 deletions
diff --git a/sound/pci/oxygen/cs2000.h b/sound/pci/oxygen/cs2000.h new file mode 100644 index 000000000000..c3501bdb5edc --- /dev/null +++ b/sound/pci/oxygen/cs2000.h | |||
@@ -0,0 +1,83 @@ | |||
1 | #ifndef CS2000_H_INCLUDED | ||
2 | #define CS2000_H_INCLUDED | ||
3 | |||
4 | #define CS2000_DEV_ID 0x01 | ||
5 | #define CS2000_DEV_CTRL 0x02 | ||
6 | #define CS2000_DEV_CFG_1 0x03 | ||
7 | #define CS2000_DEV_CFG_2 0x04 | ||
8 | #define CS2000_GLOBAL_CFG 0x05 | ||
9 | #define CS2000_RATIO_0 0x06 /* 32 bits, big endian */ | ||
10 | #define CS2000_RATIO_1 0x0a | ||
11 | #define CS2000_RATIO_2 0x0e | ||
12 | #define CS2000_RATIO_3 0x12 | ||
13 | #define CS2000_FUN_CFG_1 0x16 | ||
14 | #define CS2000_FUN_CFG_2 0x17 | ||
15 | #define CS2000_FUN_CFG_3 0x1e | ||
16 | |||
17 | /* DEV_ID */ | ||
18 | #define CS2000_DEVICE_MASK 0xf8 | ||
19 | #define CS2000_REVISION_MASK 0x07 | ||
20 | |||
21 | /* DEV_CTRL */ | ||
22 | #define CS2000_UNLOCK 0x80 | ||
23 | #define CS2000_AUX_OUT_DIS 0x02 | ||
24 | #define CS2000_CLK_OUT_DIS 0x01 | ||
25 | |||
26 | /* DEV_CFG_1 */ | ||
27 | #define CS2000_R_MOD_SEL_MASK 0xe0 | ||
28 | #define CS2000_R_MOD_SEL_1 0x00 | ||
29 | #define CS2000_R_MOD_SEL_2 0x20 | ||
30 | #define CS2000_R_MOD_SEL_4 0x40 | ||
31 | #define CS2000_R_MOD_SEL_8 0x60 | ||
32 | #define CS2000_R_MOD_SEL_1_2 0x80 | ||
33 | #define CS2000_R_MOD_SEL_1_4 0xa0 | ||
34 | #define CS2000_R_MOD_SEL_1_8 0xc0 | ||
35 | #define CS2000_R_MOD_SEL_1_16 0xe0 | ||
36 | #define CS2000_R_SEL_MASK 0x18 | ||
37 | #define CS2000_R_SEL_SHIFT 3 | ||
38 | #define CS2000_AUX_OUT_SRC_MASK 0x06 | ||
39 | #define CS2000_AUX_OUT_SRC_REF_CLK 0x00 | ||
40 | #define CS2000_AUX_OUT_SRC_CLK_IN 0x02 | ||
41 | #define CS2000_AUX_OUT_SRC_CLK_OUT 0x04 | ||
42 | #define CS2000_AUX_OUT_SRC_PLL_LOCK 0x06 | ||
43 | #define CS2000_EN_DEV_CFG_1 0x01 | ||
44 | |||
45 | /* DEV_CFG_2 */ | ||
46 | #define CS2000_LOCK_CLK_MASK 0x06 | ||
47 | #define CS2000_LOCK_CLK_SHIFT 1 | ||
48 | #define CS2000_FRAC_N_SRC_MASK 0x01 | ||
49 | #define CS2000_FRAC_N_SRC_STATIC 0x00 | ||
50 | #define CS2000_FRAC_N_SRC_DYNAMIC 0x01 | ||
51 | |||
52 | /* GLOBAL_CFG */ | ||
53 | #define CS2000_FREEZE 0x08 | ||
54 | #define CS2000_EN_DEV_CFG_2 0x01 | ||
55 | |||
56 | /* FUN_CFG_1 */ | ||
57 | #define CS2000_CLK_SKIP_EN 0x80 | ||
58 | #define CS2000_AUX_LOCK_CFG_MASK 0x40 | ||
59 | #define CS2000_AUX_LOCK_CFG_PP_HIGH 0x00 | ||
60 | #define CS2000_AUX_LOCK_CFG_OD_LOW 0x40 | ||
61 | #define CS2000_REF_CLK_DIV_MASK 0x18 | ||
62 | #define CS2000_REF_CLK_DIV_4 0x00 | ||
63 | #define CS2000_REF_CLK_DIV_2 0x08 | ||
64 | #define CS2000_REF_CLK_DIV_1 0x10 | ||
65 | |||
66 | /* FUN_CFG_2 */ | ||
67 | #define CS2000_CLK_OUT_UNL 0x10 | ||
68 | #define CS2000_L_F_RATIO_CFG_MASK 0x08 | ||
69 | #define CS2000_L_F_RATIO_CFG_20_12 0x00 | ||
70 | #define CS2000_L_F_RATIO_CFG_12_20 0x08 | ||
71 | |||
72 | /* FUN_CFG_3 */ | ||
73 | #define CS2000_CLK_IN_BW_MASK 0x70 | ||
74 | #define CS2000_CLK_IN_BW_1 0x00 | ||
75 | #define CS2000_CLK_IN_BW_2 0x10 | ||
76 | #define CS2000_CLK_IN_BW_4 0x20 | ||
77 | #define CS2000_CLK_IN_BW_8 0x30 | ||
78 | #define CS2000_CLK_IN_BW_16 0x40 | ||
79 | #define CS2000_CLK_IN_BW_32 0x50 | ||
80 | #define CS2000_CLK_IN_BW_64 0x60 | ||
81 | #define CS2000_CLK_IN_BW_128 0x70 | ||
82 | |||
83 | #endif | ||
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index eb5f015fcd23..522efde0d52e 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c | |||
@@ -91,6 +91,9 @@ | |||
91 | * CMI8788: | 91 | * CMI8788: |
92 | * | 92 | * |
93 | * I²C <-> PCM1792A | 93 | * I²C <-> PCM1792A |
94 | * <-> CS2000 (ST only) | ||
95 | * | ||
96 | * ADC1 MCLK -> REF_CLK of CS2000 (ST only) | ||
94 | * | 97 | * |
95 | * GPI 0 <- external power present (STX only) | 98 | * GPI 0 <- external power present (STX only) |
96 | * | 99 | * |
@@ -124,6 +127,7 @@ | |||
124 | #include "xonar.h" | 127 | #include "xonar.h" |
125 | #include "cm9780.h" | 128 | #include "cm9780.h" |
126 | #include "pcm1796.h" | 129 | #include "pcm1796.h" |
130 | #include "cs2000.h" | ||
127 | 131 | ||
128 | 132 | ||
129 | #define GPIO_D2X_EXT_POWER 0x0020 | 133 | #define GPIO_D2X_EXT_POWER 0x0020 |
@@ -143,12 +147,14 @@ | |||
143 | #define GPIO_ST_HP 0x0080 | 147 | #define GPIO_ST_HP 0x0080 |
144 | 148 | ||
145 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ | 149 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ |
150 | #define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /W=0 */ | ||
146 | 151 | ||
147 | 152 | ||
148 | struct xonar_pcm179x { | 153 | struct xonar_pcm179x { |
149 | struct xonar_generic generic; | 154 | struct xonar_generic generic; |
150 | unsigned int dacs; | 155 | unsigned int dacs; |
151 | u8 oversampling; | 156 | u8 oversampling; |
157 | u8 cs2000_fun_cfg_1; | ||
152 | }; | 158 | }; |
153 | 159 | ||
154 | struct xonar_hdav { | 160 | struct xonar_hdav { |
@@ -188,6 +194,11 @@ static void pcm1796_write(struct oxygen *chip, unsigned int codec, | |||
188 | pcm1796_write_i2c(chip, codec, reg, value); | 194 | pcm1796_write_i2c(chip, codec, reg, value); |
189 | } | 195 | } |
190 | 196 | ||
197 | static void cs2000_write(struct oxygen *chip, u8 reg, u8 value) | ||
198 | { | ||
199 | oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); | ||
200 | } | ||
201 | |||
191 | static void update_pcm1796_volume(struct oxygen *chip) | 202 | static void update_pcm1796_volume(struct oxygen *chip) |
192 | { | 203 | { |
193 | struct xonar_pcm179x *data = chip->model_data; | 204 | struct xonar_pcm179x *data = chip->model_data; |
@@ -292,14 +303,17 @@ static void xonar_hdav_init(struct oxygen *chip) | |||
292 | snd_component_add(chip->card, "CS5381"); | 303 | snd_component_add(chip->card, "CS5381"); |
293 | } | 304 | } |
294 | 305 | ||
295 | static void xonar_st_init(struct oxygen *chip) | 306 | static void xonar_st_init_i2c(struct oxygen *chip) |
296 | { | 307 | { |
297 | struct xonar_pcm179x *data = chip->model_data; | ||
298 | |||
299 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 308 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, |
300 | OXYGEN_2WIRE_LENGTH_8 | | 309 | OXYGEN_2WIRE_LENGTH_8 | |
301 | OXYGEN_2WIRE_INTERRUPT_MASK | | 310 | OXYGEN_2WIRE_INTERRUPT_MASK | |
302 | OXYGEN_2WIRE_SPEED_FAST); | 311 | OXYGEN_2WIRE_SPEED_FAST); |
312 | } | ||
313 | |||
314 | static void xonar_st_init_common(struct oxygen *chip) | ||
315 | { | ||
316 | struct xonar_pcm179x *data = chip->model_data; | ||
303 | 317 | ||
304 | data->generic.anti_pop_delay = 100; | 318 | data->generic.anti_pop_delay = 100; |
305 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; | 319 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; |
@@ -320,15 +334,57 @@ static void xonar_st_init(struct oxygen *chip) | |||
320 | snd_component_add(chip->card, "CS5381"); | 334 | snd_component_add(chip->card, "CS5381"); |
321 | } | 335 | } |
322 | 336 | ||
337 | static void cs2000_registers_init(struct oxygen *chip) | ||
338 | { | ||
339 | struct xonar_pcm179x *data = chip->model_data; | ||
340 | |||
341 | cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_FREEZE); | ||
342 | cs2000_write(chip, CS2000_DEV_CTRL, 0); | ||
343 | cs2000_write(chip, CS2000_DEV_CFG_1, | ||
344 | CS2000_R_MOD_SEL_1 | | ||
345 | (0 << CS2000_R_SEL_SHIFT) | | ||
346 | CS2000_AUX_OUT_SRC_REF_CLK | | ||
347 | CS2000_EN_DEV_CFG_1); | ||
348 | cs2000_write(chip, CS2000_DEV_CFG_2, | ||
349 | (0 << CS2000_LOCK_CLK_SHIFT) | | ||
350 | CS2000_FRAC_N_SRC_STATIC); | ||
351 | cs2000_write(chip, CS2000_RATIO_0 + 0, 0x00); /* 1.0 */ | ||
352 | cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10); | ||
353 | cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00); | ||
354 | cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00); | ||
355 | cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1); | ||
356 | cs2000_write(chip, CS2000_FUN_CFG_2, 0); | ||
357 | cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2); | ||
358 | } | ||
359 | |||
360 | static void xonar_st_init(struct oxygen *chip) | ||
361 | { | ||
362 | struct xonar_pcm179x *data = chip->model_data; | ||
363 | |||
364 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; | ||
365 | |||
366 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | ||
367 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S | | ||
368 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
369 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
370 | |||
371 | xonar_st_init_i2c(chip); | ||
372 | cs2000_registers_init(chip); | ||
373 | xonar_st_init_common(chip); | ||
374 | |||
375 | snd_component_add(chip->card, "CS2000"); | ||
376 | } | ||
377 | |||
323 | static void xonar_stx_init(struct oxygen *chip) | 378 | static void xonar_stx_init(struct oxygen *chip) |
324 | { | 379 | { |
325 | struct xonar_pcm179x *data = chip->model_data; | 380 | struct xonar_pcm179x *data = chip->model_data; |
326 | 381 | ||
382 | xonar_st_init_i2c(chip); | ||
327 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; | 383 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; |
328 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 384 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; |
329 | data->generic.ext_power_bit = GPI_EXT_POWER; | 385 | data->generic.ext_power_bit = GPI_EXT_POWER; |
330 | xonar_init_ext_power(chip); | 386 | xonar_init_ext_power(chip); |
331 | xonar_st_init(chip); | 387 | xonar_st_init_common(chip); |
332 | } | 388 | } |
333 | 389 | ||
334 | static void xonar_d2_cleanup(struct oxygen *chip) | 390 | static void xonar_d2_cleanup(struct oxygen *chip) |
@@ -378,12 +434,18 @@ static void xonar_hdav_resume(struct oxygen *chip) | |||
378 | xonar_enable_output(chip); | 434 | xonar_enable_output(chip); |
379 | } | 435 | } |
380 | 436 | ||
381 | static void xonar_st_resume(struct oxygen *chip) | 437 | static void xonar_stx_resume(struct oxygen *chip) |
382 | { | 438 | { |
383 | pcm1796_init(chip); | 439 | pcm1796_init(chip); |
384 | xonar_enable_output(chip); | 440 | xonar_enable_output(chip); |
385 | } | 441 | } |
386 | 442 | ||
443 | static void xonar_st_resume(struct oxygen *chip) | ||
444 | { | ||
445 | cs2000_registers_init(chip); | ||
446 | xonar_stx_resume(chip); | ||
447 | } | ||
448 | |||
387 | static void set_pcm1796_params(struct oxygen *chip, | 449 | static void set_pcm1796_params(struct oxygen *chip, |
388 | struct snd_pcm_hw_params *params) | 450 | struct snd_pcm_hw_params *params) |
389 | { | 451 | { |
@@ -396,6 +458,43 @@ static void set_pcm1796_params(struct oxygen *chip, | |||
396 | pcm1796_write(chip, i, 20, data->oversampling); | 458 | pcm1796_write(chip, i, 20, data->oversampling); |
397 | } | 459 | } |
398 | 460 | ||
461 | static void set_cs2000_params(struct oxygen *chip, | ||
462 | struct snd_pcm_hw_params *params) | ||
463 | { | ||
464 | /* XXX Why is the I2S A MCLK half the actual I2S multich MCLK? */ | ||
465 | static const u8 rate_mclks[] = { | ||
466 | [OXYGEN_RATE_32000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_128, | ||
467 | [OXYGEN_RATE_44100] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128, | ||
468 | [OXYGEN_RATE_48000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128, | ||
469 | [OXYGEN_RATE_64000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256, | ||
470 | [OXYGEN_RATE_88200] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256, | ||
471 | [OXYGEN_RATE_96000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256, | ||
472 | [OXYGEN_RATE_176400] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256, | ||
473 | [OXYGEN_RATE_192000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256, | ||
474 | }; | ||
475 | struct xonar_pcm179x *data = chip->model_data; | ||
476 | unsigned int rate_index; | ||
477 | u8 rate_mclk; | ||
478 | |||
479 | rate_index = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) | ||
480 | & OXYGEN_I2S_RATE_MASK; | ||
481 | rate_mclk = rate_mclks[rate_index]; | ||
482 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, | ||
483 | OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); | ||
484 | if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) | ||
485 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; | ||
486 | else | ||
487 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_2; | ||
488 | cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1); | ||
489 | } | ||
490 | |||
491 | static void set_st_params(struct oxygen *chip, | ||
492 | struct snd_pcm_hw_params *params) | ||
493 | { | ||
494 | set_cs2000_params(chip, params); | ||
495 | set_pcm1796_params(chip, params); | ||
496 | } | ||
497 | |||
399 | static void set_hdav_params(struct oxygen *chip, | 498 | static void set_hdav_params(struct oxygen *chip, |
400 | struct snd_pcm_hw_params *params) | 499 | struct snd_pcm_hw_params *params) |
401 | { | 500 | { |
@@ -590,7 +689,7 @@ static const struct oxygen_model model_xonar_st = { | |||
590 | .cleanup = xonar_st_cleanup, | 689 | .cleanup = xonar_st_cleanup, |
591 | .suspend = xonar_st_suspend, | 690 | .suspend = xonar_st_suspend, |
592 | .resume = xonar_st_resume, | 691 | .resume = xonar_st_resume, |
593 | .set_dac_params = set_pcm1796_params, | 692 | .set_dac_params = set_st_params, |
594 | .set_adc_params = xonar_set_cs53x1_params, | 693 | .set_adc_params = xonar_set_cs53x1_params, |
595 | .update_dac_volume = update_pcm1796_volume, | 694 | .update_dac_volume = update_pcm1796_volume, |
596 | .update_dac_mute = update_pcm1796_mute, | 695 | .update_dac_mute = update_pcm1796_mute, |
@@ -652,6 +751,8 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, | |||
652 | chip->model = model_xonar_st; | 751 | chip->model = model_xonar_st; |
653 | chip->model.shortname = "Xonar STX"; | 752 | chip->model.shortname = "Xonar STX"; |
654 | chip->model.init = xonar_stx_init; | 753 | chip->model.init = xonar_stx_init; |
754 | chip->model.resume = xonar_stx_resume; | ||
755 | chip->model.set_dac_params = set_pcm1796_params; | ||
655 | break; | 756 | break; |
656 | default: | 757 | default: |
657 | return -EINVAL; | 758 | return -EINVAL; |