Skip to content

Commit

Permalink
sound: virtuoso: fix Xonar Essence ST support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Clemens Ladisch authored and Takashi Iwai committed Sep 28, 2009
1 parent 65c3ac8 commit 268304f
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 6 deletions.
83 changes: 83 additions & 0 deletions sound/pci/oxygen/cs2000.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#ifndef CS2000_H_INCLUDED
#define CS2000_H_INCLUDED

#define CS2000_DEV_ID 0x01
#define CS2000_DEV_CTRL 0x02
#define CS2000_DEV_CFG_1 0x03
#define CS2000_DEV_CFG_2 0x04
#define CS2000_GLOBAL_CFG 0x05
#define CS2000_RATIO_0 0x06 /* 32 bits, big endian */
#define CS2000_RATIO_1 0x0a
#define CS2000_RATIO_2 0x0e
#define CS2000_RATIO_3 0x12
#define CS2000_FUN_CFG_1 0x16
#define CS2000_FUN_CFG_2 0x17
#define CS2000_FUN_CFG_3 0x1e

/* DEV_ID */
#define CS2000_DEVICE_MASK 0xf8
#define CS2000_REVISION_MASK 0x07

/* DEV_CTRL */
#define CS2000_UNLOCK 0x80
#define CS2000_AUX_OUT_DIS 0x02
#define CS2000_CLK_OUT_DIS 0x01

/* DEV_CFG_1 */
#define CS2000_R_MOD_SEL_MASK 0xe0
#define CS2000_R_MOD_SEL_1 0x00
#define CS2000_R_MOD_SEL_2 0x20
#define CS2000_R_MOD_SEL_4 0x40
#define CS2000_R_MOD_SEL_8 0x60
#define CS2000_R_MOD_SEL_1_2 0x80
#define CS2000_R_MOD_SEL_1_4 0xa0
#define CS2000_R_MOD_SEL_1_8 0xc0
#define CS2000_R_MOD_SEL_1_16 0xe0
#define CS2000_R_SEL_MASK 0x18
#define CS2000_R_SEL_SHIFT 3
#define CS2000_AUX_OUT_SRC_MASK 0x06
#define CS2000_AUX_OUT_SRC_REF_CLK 0x00
#define CS2000_AUX_OUT_SRC_CLK_IN 0x02
#define CS2000_AUX_OUT_SRC_CLK_OUT 0x04
#define CS2000_AUX_OUT_SRC_PLL_LOCK 0x06
#define CS2000_EN_DEV_CFG_1 0x01

/* DEV_CFG_2 */
#define CS2000_LOCK_CLK_MASK 0x06
#define CS2000_LOCK_CLK_SHIFT 1
#define CS2000_FRAC_N_SRC_MASK 0x01
#define CS2000_FRAC_N_SRC_STATIC 0x00
#define CS2000_FRAC_N_SRC_DYNAMIC 0x01

/* GLOBAL_CFG */
#define CS2000_FREEZE 0x08
#define CS2000_EN_DEV_CFG_2 0x01

/* FUN_CFG_1 */
#define CS2000_CLK_SKIP_EN 0x80
#define CS2000_AUX_LOCK_CFG_MASK 0x40
#define CS2000_AUX_LOCK_CFG_PP_HIGH 0x00
#define CS2000_AUX_LOCK_CFG_OD_LOW 0x40
#define CS2000_REF_CLK_DIV_MASK 0x18
#define CS2000_REF_CLK_DIV_4 0x00
#define CS2000_REF_CLK_DIV_2 0x08
#define CS2000_REF_CLK_DIV_1 0x10

/* FUN_CFG_2 */
#define CS2000_CLK_OUT_UNL 0x10
#define CS2000_L_F_RATIO_CFG_MASK 0x08
#define CS2000_L_F_RATIO_CFG_20_12 0x00
#define CS2000_L_F_RATIO_CFG_12_20 0x08

/* FUN_CFG_3 */
#define CS2000_CLK_IN_BW_MASK 0x70
#define CS2000_CLK_IN_BW_1 0x00
#define CS2000_CLK_IN_BW_2 0x10
#define CS2000_CLK_IN_BW_4 0x20
#define CS2000_CLK_IN_BW_8 0x30
#define CS2000_CLK_IN_BW_16 0x40
#define CS2000_CLK_IN_BW_32 0x50
#define CS2000_CLK_IN_BW_64 0x60
#define CS2000_CLK_IN_BW_128 0x70

#endif
113 changes: 107 additions & 6 deletions sound/pci/oxygen/xonar_pcm179x.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@
* CMI8788:
*
* I²C <-> PCM1792A
* <-> CS2000 (ST only)
*
* ADC1 MCLK -> REF_CLK of CS2000 (ST only)
*
* GPI 0 <- external power present (STX only)
*
Expand Down Expand Up @@ -124,6 +127,7 @@
#include "xonar.h"
#include "cm9780.h"
#include "pcm1796.h"
#include "cs2000.h"


#define GPIO_D2X_EXT_POWER 0x0020
Expand All @@ -143,12 +147,14 @@
#define GPIO_ST_HP 0x0080

#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */
#define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /W=0 */


struct xonar_pcm179x {
struct xonar_generic generic;
unsigned int dacs;
u8 oversampling;
u8 cs2000_fun_cfg_1;
};

struct xonar_hdav {
Expand Down Expand Up @@ -188,6 +194,11 @@ static void pcm1796_write(struct oxygen *chip, unsigned int codec,
pcm1796_write_i2c(chip, codec, reg, value);
}

static void cs2000_write(struct oxygen *chip, u8 reg, u8 value)
{
oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value);
}

static void update_pcm1796_volume(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;
Expand Down Expand Up @@ -292,14 +303,17 @@ static void xonar_hdav_init(struct oxygen *chip)
snd_component_add(chip->card, "CS5381");
}

static void xonar_st_init(struct oxygen *chip)
static void xonar_st_init_i2c(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;

oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
OXYGEN_2WIRE_LENGTH_8 |
OXYGEN_2WIRE_INTERRUPT_MASK |
OXYGEN_2WIRE_SPEED_FAST);
}

static void xonar_st_init_common(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;

data->generic.anti_pop_delay = 100;
data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
Expand All @@ -320,15 +334,57 @@ static void xonar_st_init(struct oxygen *chip)
snd_component_add(chip->card, "CS5381");
}

static void cs2000_registers_init(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;

cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_FREEZE);
cs2000_write(chip, CS2000_DEV_CTRL, 0);
cs2000_write(chip, CS2000_DEV_CFG_1,
CS2000_R_MOD_SEL_1 |
(0 << CS2000_R_SEL_SHIFT) |
CS2000_AUX_OUT_SRC_REF_CLK |
CS2000_EN_DEV_CFG_1);
cs2000_write(chip, CS2000_DEV_CFG_2,
(0 << CS2000_LOCK_CLK_SHIFT) |
CS2000_FRAC_N_SRC_STATIC);
cs2000_write(chip, CS2000_RATIO_0 + 0, 0x00); /* 1.0 */
cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10);
cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00);
cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00);
cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1);
cs2000_write(chip, CS2000_FUN_CFG_2, 0);
cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2);
}

static void xonar_st_init(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;

data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;

oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S |
OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);

xonar_st_init_i2c(chip);
cs2000_registers_init(chip);
xonar_st_init_common(chip);

snd_component_add(chip->card, "CS2000");
}

static void xonar_stx_init(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;

xonar_st_init_i2c(chip);
data->generic.ext_power_reg = OXYGEN_GPI_DATA;
data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
data->generic.ext_power_bit = GPI_EXT_POWER;
xonar_init_ext_power(chip);
xonar_st_init(chip);
xonar_st_init_common(chip);
}

static void xonar_d2_cleanup(struct oxygen *chip)
Expand Down Expand Up @@ -378,12 +434,18 @@ static void xonar_hdav_resume(struct oxygen *chip)
xonar_enable_output(chip);
}

static void xonar_st_resume(struct oxygen *chip)
static void xonar_stx_resume(struct oxygen *chip)
{
pcm1796_init(chip);
xonar_enable_output(chip);
}

static void xonar_st_resume(struct oxygen *chip)
{
cs2000_registers_init(chip);
xonar_stx_resume(chip);
}

static void set_pcm1796_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
Expand All @@ -396,6 +458,43 @@ static void set_pcm1796_params(struct oxygen *chip,
pcm1796_write(chip, i, 20, data->oversampling);
}

static void set_cs2000_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
/* XXX Why is the I2S A MCLK half the actual I2S multich MCLK? */
static const u8 rate_mclks[] = {
[OXYGEN_RATE_32000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_128,
[OXYGEN_RATE_44100] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128,
[OXYGEN_RATE_48000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128,
[OXYGEN_RATE_64000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256,
[OXYGEN_RATE_88200] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256,
[OXYGEN_RATE_96000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256,
[OXYGEN_RATE_176400] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256,
[OXYGEN_RATE_192000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256,
};
struct xonar_pcm179x *data = chip->model_data;
unsigned int rate_index;
u8 rate_mclk;

rate_index = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT)
& OXYGEN_I2S_RATE_MASK;
rate_mclk = rate_mclks[rate_index];
oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128)
data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
else
data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_2;
cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1);
}

static void set_st_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
set_cs2000_params(chip, params);
set_pcm1796_params(chip, params);
}

static void set_hdav_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
Expand Down Expand Up @@ -590,7 +689,7 @@ static const struct oxygen_model model_xonar_st = {
.cleanup = xonar_st_cleanup,
.suspend = xonar_st_suspend,
.resume = xonar_st_resume,
.set_dac_params = set_pcm1796_params,
.set_dac_params = set_st_params,
.set_adc_params = xonar_set_cs53x1_params,
.update_dac_volume = update_pcm1796_volume,
.update_dac_mute = update_pcm1796_mute,
Expand Down Expand Up @@ -652,6 +751,8 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
chip->model = model_xonar_st;
chip->model.shortname = "Xonar STX";
chip->model.init = xonar_stx_init;
chip->model.resume = xonar_stx_resume;
chip->model.set_dac_params = set_pcm1796_params;
break;
default:
return -EINVAL;
Expand Down

0 comments on commit 268304f

Please sign in to comment.