diff options
Diffstat (limited to 'sound/pci/oxygen')
-rw-r--r-- | sound/pci/oxygen/oxygen.c | 2 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_pcm.c | 10 | ||||
-rw-r--r-- | sound/pci/oxygen/virtuoso.c | 3 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_pcm179x.c | 166 |
4 files changed, 169 insertions, 12 deletions
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index ada6c256378e..74afb6b75976 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -97,7 +97,7 @@ enum { MODEL_XONAR_DGX, }; -static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { +static const struct pci_device_id oxygen_ids[] = { /* C-Media's reference design */ { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x10b0, 0x0217), .driver_data = MODEL_CMEDIA_REF }, diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index cc0bcd9f3350..02828240ba15 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -29,6 +29,9 @@ /* the multichannel DMA channel has a 24-bit counter */ #define BUFFER_BYTES_MAX_MULTICH ((1 << 24) * 4) +#define FIFO_BYTES 256 +#define FIFO_BYTES_MULTICH 1024 + #define PERIOD_BYTES_MIN 64 #define DEFAULT_BUFFER_BYTES (BUFFER_BYTES_MAX / 2) @@ -60,6 +63,7 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { .period_bytes_max = BUFFER_BYTES_MAX, .periods_min = 1, .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, + .fifo_size = FIFO_BYTES, }; static const struct snd_pcm_hardware oxygen_multichannel_hardware = { .info = SNDRV_PCM_INFO_MMAP | @@ -87,6 +91,7 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { .period_bytes_max = BUFFER_BYTES_MAX_MULTICH, .periods_min = 1, .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, + .fifo_size = FIFO_BYTES_MULTICH, }; static const struct snd_pcm_hardware oxygen_ac97_hardware = { .info = SNDRV_PCM_INFO_MMAP | @@ -106,6 +111,7 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { .period_bytes_max = BUFFER_BYTES_MAX, .periods_min = 1, .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, + .fifo_size = FIFO_BYTES, }; static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { @@ -141,6 +147,10 @@ static int oxygen_open(struct snd_pcm_substream *substream, runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_64000); runtime->hw.rate_min = 44100; + /* fall through */ + case PCM_A: + case PCM_B: + runtime->hw.fifo_size = 0; break; case PCM_MULTICH: runtime->hw.channels_max = chip->model.dac_channels_pcm; diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index dbbbacfd535e..83de6fb01021 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(id, "ID string"); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "enable card"); -static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { +static const struct pci_device_id xonar_ids[] = { { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, { OXYGEN_PCI_SUBID(0x1043, 0x8275) }, { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, @@ -52,6 +52,7 @@ static DEFINE_PCI_DEVICE_TABLE(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 }, diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index e02605931669..24109d37ca09 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -212,6 +212,9 @@ #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 */ @@ -419,6 +422,7 @@ static void xonar_st_init_common(struct oxygen *chip) data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; data->dacs = chip->model.dac_channels_mixer / 2; + data->h6 = chip->model.dac_channels_mixer > 2; data->hp_gain_offset = 2*-18; pcm1796_init(chip); @@ -499,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); @@ -795,11 +844,11 @@ static int st_output_switch_put(struct snd_kcontrol *ctl, static int st_hp_volume_offset_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { - static const char *const names[3] = { - "< 64 ohms", "64-300 ohms", "300-600 ohms" + static const char *const names[4] = { + "< 32 ohms", "32-64 ohms", "64-300 ohms", "300-600 ohms" }; - return snd_ctl_enum_info(info, 1, 3, names); + return snd_ctl_enum_info(info, 1, 4, names); } static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, @@ -809,12 +858,14 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, struct xonar_pcm179x *data = chip->model_data; mutex_lock(&chip->mutex); - if (data->hp_gain_offset < 2*-6) + if (data->hp_gain_offset < 2*-12) value->value.enumerated.item[0] = 0; - else if (data->hp_gain_offset < 0) + else if (data->hp_gain_offset < 2*-6) value->value.enumerated.item[0] = 1; - else + else if (data->hp_gain_offset < 0) value->value.enumerated.item[0] = 2; + else + value->value.enumerated.item[0] = 3; mutex_unlock(&chip->mutex); return 0; } @@ -823,13 +874,13 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, static int st_hp_volume_offset_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { - static const s8 offsets[] = { 2*-18, 2*-6, 0 }; + static const s8 offsets[] = { 2*-18, 2*-12, 2*-6, 0 }; struct oxygen *chip = ctl->private_data; struct xonar_pcm179x *data = chip->model_data; s8 offset; int changed; - if (value->value.enumerated.item[0] > 2) + if (value->value.enumerated.item[0] > 3) return -EINVAL; offset = offsets[value->value.enumerated.item[0]]; mutex_lock(&chip->mutex); @@ -859,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) { @@ -946,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) { @@ -1140,12 +1269,29 @@ int get_xonar_pcm179x_model(struct oxygen *chip, break; case 0x85f4: chip->model = model_xonar_st; - /* TODO: daughterboard support */ - chip->model.shortname = "Xonar STX II"; + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); + switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { + default: + chip->model.shortname = "Xonar STX II"; + break; + case GPIO_DB_H6: + chip->model.shortname = "Xonar STX II+H6"; + chip->model.dac_channels_pcm = 8; + chip->model.dac_channels_mixer = 8; + chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); + break; + } chip->model.init = xonar_stx_init; 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; } |