ALSA: oxygen: Xonar DG(X): modify playback output select
authorRoman Volkov <v1ron@mail.ru>
Fri, 24 Jan 2014 12:18:15 +0000 (16:18 +0400)
committerClemens Ladisch <clemens@ladisch.de>
Wed, 29 Jan 2014 19:45:50 +0000 (20:45 +0100)
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>
sound/pci/oxygen/xonar_dg.c
sound/pci/oxygen/xonar_dg.h
sound/pci/oxygen/xonar_dg_mixer.c

index d12d83554abbb2bdaf3801eafcae80eee644737f..6cec934e66287f73ec2cc45996131823ee4acea1 100644 (file)
@@ -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,
index 0941ca2e0ca219fe15166f59e083ffdff1100d40..a5cb75121f40895e99108b50f0859faccec1373e 100644 (file)
@@ -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;
index 7e9fc4af81bdfbbeae051d502f832d15475c756a..6dfe6355474285bc8444772f452e8a6e619ec735 100644 (file)
 #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,