ALSA: virtuoso: add partial Xonar Xense support
authorHarley Griggs <hgriggs@posteo.co.uk>
Wed, 10 Sep 2014 18:58:25 +0000 (19:58 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 22 Sep 2014 06:55:15 +0000 (08:55 +0200)
This patch adds partial support for the Xonar Xense.

[trivial coding style fixes by tiwai]

Signed-off-by: Harley Griggs <hgriggs@posteo.co.uk>
Acked-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/oxygen/virtuoso.c
sound/pci/oxygen/xonar_pcm179x.c

index 7b317a2..83de6fb 100644 (file)
@@ -52,6 +52,7 @@ static const struct pci_device_id xonar_ids[] = {
        { OXYGEN_PCI_SUBID(0x1043, 0x835d) },
        { OXYGEN_PCI_SUBID(0x1043, 0x835e) },
        { OXYGEN_PCI_SUBID(0x1043, 0x838e) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x8428) },
        { OXYGEN_PCI_SUBID(0x1043, 0x8522) },
        { OXYGEN_PCI_SUBID(0x1043, 0x85f4) },
        { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
index 0d6a805..24109d3 100644 (file)
 #define GPIO_ST_MAGIC          0x0040
 #define GPIO_ST_HP             0x0080
 
+#define GPIO_XENSE_OUTPUT_ENABLE       (0x0001 | 0x0010 | 0x0020)
+#define GPIO_XENSE_SPEAKERS            0x0080
+
 #define I2C_DEVICE_PCM1796(i)  (0x98 + ((i) << 1))     /* 10011, ii, /W=0 */
 #define I2C_DEVICE_CS2000      0x9c                    /* 100111, 0, /W=0 */
 
@@ -500,6 +503,51 @@ static void xonar_stx_init(struct oxygen *chip)
        xonar_st_init_common(chip);
 }
 
+static void xonar_xense_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       data->generic.ext_power_reg = OXYGEN_GPI_DATA;
+       data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+       data->generic.ext_power_bit = GPI_EXT_POWER;
+       xonar_init_ext_power(chip);
+
+       data->generic.anti_pop_delay = 100;
+       data->has_cs2000 = 1;
+       data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;
+
+       oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
+               OXYGEN_RATE_48000 |
+               OXYGEN_I2S_FORMAT_I2S |
+               OXYGEN_I2S_MCLK(MCLK_512) |
+               OXYGEN_I2S_BITS_16 |
+               OXYGEN_I2S_MASTER |
+               OXYGEN_I2S_BCLK_64);
+
+       xonar_st_init_i2c(chip);
+       cs2000_registers_init(chip);
+
+       data->generic.output_enable_bit = GPIO_XENSE_OUTPUT_ENABLE;
+       data->dacs = 1;
+       data->hp_gain_offset = 2*-18;
+
+       pcm1796_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+               GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+               GPIO_ST_MAGIC | GPIO_XENSE_SPEAKERS);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+               GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+               GPIO_XENSE_SPEAKERS);
+
+       xonar_init_cs53x1(chip);
+       xonar_enable_output(chip);
+
+       snd_component_add(chip->card, "PCM1796");
+       snd_component_add(chip->card, "CS5381");
+       snd_component_add(chip->card, "CS2000");
+}
+
 static void xonar_d2_cleanup(struct oxygen *chip)
 {
        xonar_disable_output(chip);
@@ -862,6 +910,67 @@ static const struct snd_kcontrol_new st_controls[] = {
        },
 };
 
+static int xense_output_switch_get(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 gpio;
+
+       gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       if (gpio & GPIO_XENSE_SPEAKERS)
+               value->value.enumerated.item[0] = 0;
+       else if (!(gpio & GPIO_XENSE_SPEAKERS) && (gpio & GPIO_ST_HP_REAR))
+               value->value.enumerated.item[0] = 1;
+       else
+               value->value.enumerated.item[0] = 2;
+       return 0;
+}
+
+static int xense_output_switch_put(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+       u16 gpio_old, gpio;
+
+       mutex_lock(&chip->mutex);
+       gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       gpio = gpio_old;
+       switch (value->value.enumerated.item[0]) {
+       case 0:
+               gpio |= GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR;
+               break;
+       case 1:
+               gpio = (gpio | GPIO_ST_HP_REAR) & ~GPIO_XENSE_SPEAKERS;
+               break;
+       case 2:
+               gpio &= ~(GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR);
+               break;
+       }
+       oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
+       data->hp_active = !(gpio & GPIO_XENSE_SPEAKERS);
+       update_pcm1796_volume(chip);
+       mutex_unlock(&chip->mutex);
+       return gpio != gpio_old;
+}
+
+static const struct snd_kcontrol_new xense_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Output",
+               .info = st_output_switch_info,
+               .get = xense_output_switch_get,
+               .put = xense_output_switch_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphones Impedance Playback Enum",
+               .info = st_hp_volume_offset_info,
+               .get = st_hp_volume_offset_get,
+               .put = st_hp_volume_offset_put,
+       },
+};
+
 static void xonar_line_mic_ac97_switch(struct oxygen *chip,
                                       unsigned int reg, unsigned int mute)
 {
@@ -949,6 +1058,23 @@ static int xonar_st_mixer_init(struct oxygen *chip)
        return 0;
 }
 
+static int xonar_xense_mixer_init(struct oxygen *chip)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(xense_controls); ++i) {
+               err = snd_ctl_add(chip->card,
+               snd_ctl_new1(&xense_controls[i], chip));
+               if (err < 0)
+                       return err;
+       }
+       err = add_pcm1796_controls(chip);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
 static void dump_pcm1796_registers(struct oxygen *chip,
                                   struct snd_info_buffer *buffer)
 {
@@ -1159,6 +1285,13 @@ int get_xonar_pcm179x_model(struct oxygen *chip,
                chip->model.resume = xonar_stx_resume;
                chip->model.set_dac_params = set_pcm1796_params;
                break;
+       case 0x8428:
+               chip->model = model_xonar_st;
+               chip->model.shortname = "Xonar Xense";
+               chip->model.chip = "AV100";
+               chip->model.init = xonar_xense_init;
+               chip->model.mixer_init = xonar_xense_mixer_init;
+               break;
        default:
                return -EINVAL;
        }