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>

authored by Roman Volkov and committed by Clemens Ladisch 2809cb84 3dd77654

+47 -33
+1 -1
sound/pci/oxygen/xonar_dg.c
··· 268 268 struct dg *data = chip->model_data; 269 269 unsigned int routing = 0; 270 270 271 - switch (data->pcm_output) { 271 + switch (data->output_sel) { 272 272 case PLAYBACK_DST_HP: 273 273 case PLAYBACK_DST_HP_FP: 274 274 oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+1 -2
sound/pci/oxygen/xonar_dg.h
··· 27 27 /* shadow copy of the CS4245 register space */ 28 28 unsigned char cs4245_shadow[17]; 29 29 /* output select: headphone/speakers */ 30 - unsigned char pcm_output; 31 - unsigned int output_sel; 30 + unsigned char output_sel; 32 31 s8 input_vol[4][2]; 33 32 unsigned int input_sel; 34 33 u8 hp_vol_att;
+45 -30
sound/pci/oxygen/xonar_dg_mixer.c
··· 27 27 #include "xonar_dg.h" 28 28 #include "cs4245.h" 29 29 30 - static int output_switch_info(struct snd_kcontrol *ctl, 30 + /* analog output select */ 31 + 32 + static int output_select_apply(struct oxygen *chip) 33 + { 34 + struct dg *data = chip->model_data; 35 + 36 + data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK; 37 + if (data->output_sel == PLAYBACK_DST_HP) { 38 + /* mute FP (aux output) amplifier, switch rear jack to CS4245 */ 39 + oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 40 + } else if (data->output_sel == PLAYBACK_DST_HP_FP) { 41 + /* 42 + * Unmute FP amplifier, switch rear jack to CS4361; 43 + * I2S channels 2,3,4 should be inactive. 44 + */ 45 + oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 46 + data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC; 47 + } else { 48 + /* 49 + * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp., 50 + * and change playback routing. 51 + */ 52 + oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 53 + } 54 + return cs4245_write_spi(chip, CS4245_SIGNAL_SEL); 55 + } 56 + 57 + static int output_select_info(struct snd_kcontrol *ctl, 31 58 struct snd_ctl_elem_info *info) 32 59 { 33 60 static const char *const names[3] = { 34 - "Speakers", "Headphones", "FP Headphones" 61 + "Stereo Headphones", 62 + "Stereo Headphones FP", 63 + "Multichannel", 35 64 }; 36 65 37 66 return snd_ctl_enum_info(info, 1, 3, names); 38 67 } 39 68 40 - static int output_switch_get(struct snd_kcontrol *ctl, 69 + static int output_select_get(struct snd_kcontrol *ctl, 41 70 struct snd_ctl_elem_value *value) 42 71 { 43 72 struct oxygen *chip = ctl->private_data; ··· 78 49 return 0; 79 50 } 80 51 81 - static int output_switch_put(struct snd_kcontrol *ctl, 52 + static int output_select_put(struct snd_kcontrol *ctl, 82 53 struct snd_ctl_elem_value *value) 83 54 { 84 55 struct oxygen *chip = ctl->private_data; 85 56 struct dg *data = chip->model_data; 86 - u8 reg; 87 - int changed; 88 - 89 - if (value->value.enumerated.item[0] > 2) 90 - return -EINVAL; 57 + unsigned int new = value->value.enumerated.item[0]; 58 + int changed = 0; 59 + int ret; 91 60 92 61 mutex_lock(&chip->mutex); 93 - changed = value->value.enumerated.item[0] != data->output_sel; 94 - if (changed) { 95 - data->output_sel = value->value.enumerated.item[0]; 96 - 97 - reg = data->cs4245_shadow[CS4245_SIGNAL_SEL] & 98 - ~CS4245_A_OUT_SEL_MASK; 99 - reg |= data->output_sel == 2 ? 100 - CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ; 101 - cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg); 102 - 103 - cs4245_write_cached(chip, CS4245_DAC_A_CTRL, 104 - data->output_sel ? data->hp_vol_att : 0); 105 - cs4245_write_cached(chip, CS4245_DAC_B_CTRL, 106 - data->output_sel ? data->hp_vol_att : 0); 107 - 108 - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 109 - data->output_sel == 1 ? GPIO_HP_REAR : 0, 110 - GPIO_HP_REAR); 62 + if (data->output_sel != new) { 63 + data->output_sel = new; 64 + ret = output_select_apply(chip); 65 + changed = ret >= 0 ? 1 : ret; 66 + oxygen_update_dac_routing(chip); 111 67 } 112 68 mutex_unlock(&chip->mutex); 69 + 113 70 return changed; 114 71 } 115 72 ··· 316 301 { 317 302 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 318 303 .name = "Analog Output Playback Enum", 319 - .info = output_switch_info, 320 - .get = output_switch_get, 321 - .put = output_switch_put, 304 + .info = output_select_info, 305 + .get = output_select_get, 306 + .put = output_select_put, 322 307 }, 323 308 { 324 309 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,