aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2009-09-28 05:15:01 -0400
committerTakashi Iwai <tiwai@suse.de>2009-09-28 05:53:51 -0400
commit268304f4c4f0b8677d67400f04ad4e0271ec3742 (patch)
tree145c5e09c01962e8a228174ca52b9a95d723aac4 /sound/pci
parent65c3ac885ce9852852b895a4a62212f62cb5f2e9 (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/pci')
-rw-r--r--sound/pci/oxygen/cs2000.h83
-rw-r--r--sound/pci/oxygen/xonar_pcm179x.c113
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
148struct xonar_pcm179x { 153struct 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
154struct xonar_hdav { 160struct 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
197static void cs2000_write(struct oxygen *chip, u8 reg, u8 value)
198{
199 oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value);
200}
201
191static void update_pcm1796_volume(struct oxygen *chip) 202static 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
295static void xonar_st_init(struct oxygen *chip) 306static 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
314static 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
337static 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
360static 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
323static void xonar_stx_init(struct oxygen *chip) 378static 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
334static void xonar_d2_cleanup(struct oxygen *chip) 390static 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
381static void xonar_st_resume(struct oxygen *chip) 437static 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
443static void xonar_st_resume(struct oxygen *chip)
444{
445 cs2000_registers_init(chip);
446 xonar_stx_resume(chip);
447}
448
387static void set_pcm1796_params(struct oxygen *chip, 449static 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
461static 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
491static 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
399static void set_hdav_params(struct oxygen *chip, 498static 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;