Skip to content

Commit

Permalink
sound: oxygen: add stereo upmixing to center/LFE channels
Browse files Browse the repository at this point in the history
Add the possibility to route a mix of the two channels of stereo data to
the center and LFE outputs.  This is implemented only for models where
the DACs support this, i.e., for the Xonar D1 and DX.

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 75919d7 commit 3d8bb45
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 21 deletions.
1 change: 1 addition & 0 deletions sound/pci/oxygen/oxygen.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct oxygen_model {
struct snd_pcm_hw_params *params);
void (*update_dac_volume)(struct oxygen *chip);
void (*update_dac_mute)(struct oxygen *chip);
void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed);
void (*gpio_changed)(struct oxygen *chip);
void (*uart_input)(struct oxygen *chip);
void (*ac97_switch)(struct oxygen *chip,
Expand Down
33 changes: 24 additions & 9 deletions sound/pci/oxygen/oxygen_mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,15 @@ static int dac_mute_put(struct snd_kcontrol *ctl,

static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
{
static const char *const names[3] = {
"Front", "Front+Surround", "Front+Surround+Back"
static const char *const names[5] = {
"Front",
"Front+Surround",
"Front+Surround+Back",
"Front+Surround+Center/LFE",
"Front+Surround+Center/LFE+Back",
};
struct oxygen *chip = ctl->private_data;
unsigned int count = 2 + (chip->model.dac_channels == 8);
unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;

info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
info->count = 1;
Expand All @@ -127,7 +131,7 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
void oxygen_update_dac_routing(struct oxygen *chip)
{
/* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */
static const unsigned int reg_values[3] = {
static const unsigned int reg_values[5] = {
/* stereo -> front */
(0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
(1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
Expand All @@ -143,6 +147,16 @@ void oxygen_update_dac_routing(struct oxygen *chip)
(0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
(2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
(0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
/* stereo -> front+surround+center/LFE */
(0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
(0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
(0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
(3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
/* stereo -> front+surround+center/LFE+back */
(0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
(0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
(0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
(0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
};
u8 channels;
unsigned int reg_value;
Expand All @@ -167,22 +181,23 @@ void oxygen_update_dac_routing(struct oxygen *chip)
OXYGEN_PLAY_DAC1_SOURCE_MASK |
OXYGEN_PLAY_DAC2_SOURCE_MASK |
OXYGEN_PLAY_DAC3_SOURCE_MASK);
if (chip->model.update_center_lfe_mix)
chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
}

static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
{
struct oxygen *chip = ctl->private_data;
unsigned int count = 2 + (chip->model.dac_channels == 8);
unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
int changed;

if (value->value.enumerated.item[0] >= count)
return -EINVAL;
mutex_lock(&chip->mutex);
changed = value->value.enumerated.item[0] != chip->dac_routing;
if (changed) {
chip->dac_routing = min(value->value.enumerated.item[0],
count - 1);
spin_lock_irq(&chip->reg_lock);
chip->dac_routing = value->value.enumerated.item[0];
oxygen_update_dac_routing(chip);
spin_unlock_irq(&chip->reg_lock);
}
mutex_unlock(&chip->mutex);
return changed;
Expand Down
6 changes: 4 additions & 2 deletions sound/pci/oxygen/oxygen_pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;

mutex_lock(&chip->mutex);
spin_lock_irq(&chip->reg_lock);
oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
OXYGEN_SPDIF_OUT_ENABLE);
Expand All @@ -446,6 +447,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
OXYGEN_SPDIF_OUT_RATE_MASK);
oxygen_update_spdif_source(chip);
spin_unlock_irq(&chip->reg_lock);
mutex_unlock(&chip->mutex);
return 0;
}

Expand All @@ -459,6 +461,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;

mutex_lock(&chip->mutex);
spin_lock_irq(&chip->reg_lock);
oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS,
oxygen_play_channels(hw_params),
Expand All @@ -475,12 +478,11 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
OXYGEN_I2S_FORMAT_MASK |
OXYGEN_I2S_MCLK_MASK |
OXYGEN_I2S_BITS_MASK);
oxygen_update_dac_routing(chip);
oxygen_update_spdif_source(chip);
spin_unlock_irq(&chip->reg_lock);

mutex_lock(&chip->mutex);
chip->model.set_dac_params(chip, hw_params);
oxygen_update_dac_routing(chip);
mutex_unlock(&chip->mutex);
return 0;
}
Expand Down
39 changes: 29 additions & 10 deletions sound/pci/oxygen/xonar_cs43xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ struct xonar_cs43xx {
struct xonar_generic generic;
u8 cs4398_fm;
u8 cs4362a_fm;
u8 cs4362a_fm_c;
};

static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
Expand Down Expand Up @@ -128,7 +129,7 @@ static void cs43xx_init(struct oxygen *chip)
cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE);
cs4362a_write(chip, 0x05, 0);
cs4362a_write(chip, 0x06, data->cs4362a_fm);
cs4362a_write(chip, 0x09, data->cs4362a_fm);
cs4362a_write(chip, 0x09, data->cs4362a_fm_c);
cs4362a_write(chip, 0x0c, data->cs4362a_fm);
update_cs43xx_volume(chip);
update_cs43xx_mute(chip);
Expand All @@ -146,6 +147,7 @@ static void xonar_d1_init(struct oxygen *chip)
data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
data->cs4362a_fm = CS4362A_FM_SINGLE |
CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
data->cs4362a_fm_c = data->cs4362a_fm;

oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
OXYGEN_2WIRE_LENGTH_8 |
Expand Down Expand Up @@ -202,25 +204,41 @@ static void set_cs43xx_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
struct xonar_cs43xx *data = chip->model_data;
u8 cs4398_fm, cs4362a_fm;

data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST;
data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
if (params_rate(params) <= 50000) {
data->cs4398_fm |= CS4398_FM_SINGLE;
data->cs4362a_fm |= CS4362A_FM_SINGLE;
cs4398_fm = CS4398_FM_SINGLE;
cs4362a_fm = CS4362A_FM_SINGLE;
} else if (params_rate(params) <= 100000) {
data->cs4398_fm |= CS4398_FM_DOUBLE;
data->cs4362a_fm |= CS4362A_FM_DOUBLE;
cs4398_fm = CS4398_FM_DOUBLE;
cs4362a_fm = CS4362A_FM_DOUBLE;
} else {
data->cs4398_fm |= CS4398_FM_QUAD;
data->cs4362a_fm |= CS4362A_FM_QUAD;
cs4398_fm = CS4398_FM_QUAD;
cs4362a_fm = CS4362A_FM_QUAD;
}
data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST | cs4398_fm;
data->cs4362a_fm =
(data->cs4362a_fm & ~CS4362A_FM_MASK) | cs4362a_fm;
data->cs4362a_fm_c =
(data->cs4362a_fm_c & ~CS4362A_FM_MASK) | cs4362a_fm;
cs4398_write(chip, 2, data->cs4398_fm);
cs4362a_write(chip, 0x06, data->cs4362a_fm);
cs4362a_write(chip, 0x09, data->cs4362a_fm);
cs4362a_write(chip, 0x09, data->cs4362a_fm_c);
cs4362a_write(chip, 0x0c, data->cs4362a_fm);
}

static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed)
{
struct xonar_cs43xx *data = chip->model_data;

data->cs4362a_fm_c &= ~CS4362A_ATAPI_MASK;
if (mixed)
data->cs4362a_fm_c |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR;
else
data->cs4362a_fm_c |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
cs4362a_write(chip, 0x09, data->cs4362a_fm_c);
}

static const struct snd_kcontrol_new front_panel_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Front Panel Switch",
Expand Down Expand Up @@ -269,6 +287,7 @@ static const struct oxygen_model model_xonar_d1 = {
.set_adc_params = xonar_set_cs53x1_params,
.update_dac_volume = update_cs43xx_volume,
.update_dac_mute = update_cs43xx_mute,
.update_center_lfe_mix = update_cs43xx_center_lfe_mix,
.ac97_switch = xonar_d1_line_mic_ac97_switch,
.dac_tlv = cs4362a_db_scale,
.model_data_size = sizeof(struct xonar_cs43xx),
Expand Down

0 comments on commit 3d8bb45

Please sign in to comment.