|
@@ -212,6 +212,9 @@
|
|
#define GPIO_ST_MAGIC 0x0040
|
|
#define GPIO_ST_MAGIC 0x0040
|
|
#define GPIO_ST_HP 0x0080
|
|
#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_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */
|
|
#define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /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);
|
|
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)
|
|
static void xonar_d2_cleanup(struct oxygen *chip)
|
|
{
|
|
{
|
|
xonar_disable_output(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,
|
|
static void xonar_line_mic_ac97_switch(struct oxygen *chip,
|
|
unsigned int reg, unsigned int mute)
|
|
unsigned int reg, unsigned int mute)
|
|
{
|
|
{
|
|
@@ -949,6 +1058,23 @@ static int xonar_st_mixer_init(struct oxygen *chip)
|
|
return 0;
|
|
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,
|
|
static void dump_pcm1796_registers(struct oxygen *chip,
|
|
struct snd_info_buffer *buffer)
|
|
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.resume = xonar_stx_resume;
|
|
chip->model.set_dac_params = set_pcm1796_params;
|
|
chip->model.set_dac_params = set_pcm1796_params;
|
|
break;
|
|
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:
|
|
default:
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|