Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efbeb071 authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Takashi Iwai
Browse files

ALSA: oxygen: fix output routing on Xonar DG



This card uses separate I2S outputs for the front speakers and
headphones, and reverses the order of the three speaker outputs.
To work around this, add a model-specific callback to adjust the
controller's playback routing.

Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent fdbc5d1b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -92,6 +92,8 @@ struct oxygen_model {
	void (*update_dac_volume)(struct oxygen *chip);
	void (*update_dac_mute)(struct oxygen *chip);
	void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed);
	unsigned int (*adjust_dac_routing)(struct oxygen *chip,
					   unsigned int play_routing);
	void (*gpio_changed)(struct oxygen *chip);
	void (*uart_input)(struct oxygen *chip);
	void (*ac97_switch)(struct oxygen *chip,
+2 −0
Original line number Diff line number Diff line
@@ -180,6 +180,8 @@ void oxygen_update_dac_routing(struct oxygen *chip)
			    (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
			    (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
			    (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
	if (chip->model.adjust_dac_routing)
		reg_value = chip->model.adjust_dac_routing(chip, reg_value);
	oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value,
			      OXYGEN_PLAY_DAC0_SOURCE_MASK |
			      OXYGEN_PLAY_DAC1_SOURCE_MASK |
+36 −0
Original line number Diff line number Diff line
@@ -24,6 +24,11 @@
 *
 *   SPI 0 -> CS4245
 *
 *   I²S 1 -> CS4245
 *   I²S 2 -> CS4361 (center/LFE)
 *   I²S 3 -> CS4361 (surround)
 *   I²S 4 -> CS4361 (front)
 *
 *   GPIO 3 <- ?
 *   GPIO 4 <- headphone detect
 *   GPIO 5 -> route input jack to line-in (0) or mic-in (1)
@@ -36,6 +41,7 @@
 *   input 1 <- aux
 *   input 2 <- front mic
 *   input 4 <- line/mic
 *   DAC out -> headphones
 *   aux out -> front panel headphones
 */

@@ -207,6 +213,35 @@ static void set_cs4245_adc_params(struct oxygen *chip,
	cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
}

static inline unsigned int shift_bits(unsigned int value,
				      unsigned int shift_from,
				      unsigned int shift_to,
				      unsigned int mask)
{
	if (shift_from < shift_to)
		return (value << (shift_to - shift_from)) & mask;
	else
		return (value >> (shift_from - shift_to)) & mask;
}

static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
					  unsigned int play_routing)
{
	return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
	       shift_bits(play_routing,
			  OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
			  OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
			  OXYGEN_PLAY_DAC1_SOURCE_MASK) |
	       shift_bits(play_routing,
			  OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
			  OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
			  OXYGEN_PLAY_DAC2_SOURCE_MASK) |
	       shift_bits(play_routing,
			  OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
			  OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
			  OXYGEN_PLAY_DAC3_SOURCE_MASK);
}

static int output_switch_info(struct snd_kcontrol *ctl,
			      struct snd_ctl_elem_info *info)
{
@@ -557,6 +592,7 @@ struct oxygen_model model_xonar_dg = {
	.resume = dg_resume,
	.set_dac_params = set_cs4245_dac_params,
	.set_adc_params = set_cs4245_adc_params,
	.adjust_dac_routing = adjust_dg_dac_routing,
	.dump_registers = dump_cs4245_registers,
	.model_data_size = sizeof(struct dg),
	.device_config = PLAYBACK_0_TO_I2S |