summary refs log tree commit diff
path: root/sound
diff options
context:
space:
mode:
authorRoman Volkov <v1ron@mail.ru>2014-01-24 16:18:15 +0400
committerClemens Ladisch <clemens@ladisch.de>2014-01-29 20:45:50 +0100
commit2809cb84d1672b639a4a41a0fa077fb554699072 (patch)
tree32b117862dc307aa0f579191ced847d0c54ad528 /sound
parent3dd77654fb1d7f68b9739f3039bad8dbbc0739f8 (diff)
downloadlinux-2809cb84d1672b639a4a41a0fa077fb554699072.tar.gz
ALSA: oxygen: Xonar DG(X): modify playback output select
Change the order of elements in the output select control. This will
reduce the number of relay switches. Change 'put' function to call the
oxygen_update_dac_routing() function. Otherwise multichannel playback
does not work. Also there is a new function to apply settings, this
prevents from duplicating the code.

Signed-off-by: Roman Volkov <v1ron@mail.ru>
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/oxygen/xonar_dg.c2
-rw-r--r--sound/pci/oxygen/xonar_dg.h3
-rw-r--r--sound/pci/oxygen/xonar_dg_mixer.c75
3 files changed, 47 insertions, 33 deletions
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index d12d83554abb..6cec934e6628 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -268,7 +268,7 @@ unsigned int adjust_dg_dac_routing(struct oxygen *chip,
 	struct dg *data = chip->model_data;
 	unsigned int routing = 0;
 
-	switch (data->pcm_output) {
+	switch (data->output_sel) {
 	case PLAYBACK_DST_HP:
 	case PLAYBACK_DST_HP_FP:
 		oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h
index 0941ca2e0ca2..a5cb75121f40 100644
--- a/sound/pci/oxygen/xonar_dg.h
+++ b/sound/pci/oxygen/xonar_dg.h
@@ -27,8 +27,7 @@ struct dg {
 	/* shadow copy of the CS4245 register space */
 	unsigned char cs4245_shadow[17];
 	/* output select: headphone/speakers */
-	unsigned char pcm_output;
-	unsigned int output_sel;
+	unsigned char output_sel;
 	s8 input_vol[4][2];
 	unsigned int input_sel;
 	u8 hp_vol_att;
diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c
index 7e9fc4af81bd..6dfe63554742 100644
--- a/sound/pci/oxygen/xonar_dg_mixer.c
+++ b/sound/pci/oxygen/xonar_dg_mixer.c
@@ -27,17 +27,46 @@
 #include "xonar_dg.h"
 #include "cs4245.h"
 
-static int output_switch_info(struct snd_kcontrol *ctl,
+/* analog output select */
+
+static int output_select_apply(struct oxygen *chip)
+{
+	struct dg *data = chip->model_data;
+
+	data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK;
+	if (data->output_sel == PLAYBACK_DST_HP) {
+		/* mute FP (aux output) amplifier, switch rear jack to CS4245 */
+		oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+	} else if (data->output_sel == PLAYBACK_DST_HP_FP) {
+		/*
+		 * Unmute FP amplifier, switch rear jack to CS4361;
+		 * I2S channels 2,3,4 should be inactive.
+		 */
+		oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+		data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC;
+	} else {
+		/*
+		 * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp.,
+		 * and change playback routing.
+		 */
+		oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+	}
+	return cs4245_write_spi(chip, CS4245_SIGNAL_SEL);
+}
+
+static int output_select_info(struct snd_kcontrol *ctl,
 			      struct snd_ctl_elem_info *info)
 {
 	static const char *const names[3] = {
-		"Speakers", "Headphones", "FP Headphones"
+		"Stereo Headphones",
+		"Stereo Headphones FP",
+		"Multichannel",
 	};
 
 	return snd_ctl_enum_info(info, 1, 3, names);
 }
 
-static int output_switch_get(struct snd_kcontrol *ctl,
+static int output_select_get(struct snd_kcontrol *ctl,
 			     struct snd_ctl_elem_value *value)
 {
 	struct oxygen *chip = ctl->private_data;
@@ -49,38 +78,24 @@ static int output_switch_get(struct snd_kcontrol *ctl,
 	return 0;
 }
 
-static int output_switch_put(struct snd_kcontrol *ctl,
+static int output_select_put(struct snd_kcontrol *ctl,
 			     struct snd_ctl_elem_value *value)
 {
 	struct oxygen *chip = ctl->private_data;
 	struct dg *data = chip->model_data;
-	u8 reg;
-	int changed;
-
-	if (value->value.enumerated.item[0] > 2)
-		return -EINVAL;
+	unsigned int new = value->value.enumerated.item[0];
+	int changed = 0;
+	int ret;
 
 	mutex_lock(&chip->mutex);
-	changed = value->value.enumerated.item[0] != data->output_sel;
-	if (changed) {
-		data->output_sel = value->value.enumerated.item[0];
-
-		reg = data->cs4245_shadow[CS4245_SIGNAL_SEL] &
-						~CS4245_A_OUT_SEL_MASK;
-		reg |= data->output_sel == 2 ?
-				CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
-		cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
-
-		cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
-				    data->output_sel ? data->hp_vol_att : 0);
-		cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
-				    data->output_sel ? data->hp_vol_att : 0);
-
-		oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
-				      data->output_sel == 1 ? GPIO_HP_REAR : 0,
-				      GPIO_HP_REAR);
+	if (data->output_sel != new) {
+		data->output_sel = new;
+		ret = output_select_apply(chip);
+		changed = ret >= 0 ? 1 : ret;
+		oxygen_update_dac_routing(chip);
 	}
 	mutex_unlock(&chip->mutex);
+
 	return changed;
 }
 
@@ -301,9 +316,9 @@ static const struct snd_kcontrol_new dg_controls[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Analog Output Playback Enum",
-		.info = output_switch_info,
-		.get = output_switch_get,
-		.put = output_switch_put,
+		.info = output_select_info,
+		.get = output_select_get,
+		.put = output_select_put,
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,