diff options
Diffstat (limited to 'sound/pci/oxygen')
-rw-r--r-- | sound/pci/oxygen/Makefile | 2 | ||||
-rw-r--r-- | sound/pci/oxygen/hifier.c | 239 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen.c | 133 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen.h | 4 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 18 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_mixer.c | 55 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_pcm.c | 14 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar.h | 2 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_cs43xx.c | 70 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_lib.c | 6 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_pcm179x.c | 234 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_wm87x6.c | 73 |
12 files changed, 478 insertions, 372 deletions
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index acd8f15f7bf..bd67c0d7779 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile @@ -1,10 +1,8 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o -snd-hifier-objs := hifier.o snd-oxygen-objs := oxygen.o snd-virtuoso-objs := virtuoso.o xonar_lib.o \ xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o -obj-$(CONFIG_SND_HIFIER) += snd-hifier.o obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c deleted file mode 100644 index 5a87d683691..00000000000 --- a/sound/pci/oxygen/hifier.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2. - * - * This driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this driver; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * CMI8788: - * - * SPI 0 -> AK4396 - */ - -#include <linux/delay.h> -#include <linux/pci.h> -#include <sound/control.h> -#include <sound/core.h> -#include <sound/initval.h> -#include <sound/pcm.h> -#include <sound/tlv.h> -#include "oxygen.h" -#include "ak4396.h" - -MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); -MODULE_DESCRIPTION("TempoTec HiFier driver"); -MODULE_LICENSE("GPL v2"); - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "card index"); -module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string"); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "enable card"); - -static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = { - { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, - { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, - { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, - { } -}; -MODULE_DEVICE_TABLE(pci, hifier_ids); - -struct hifier_data { - u8 ak4396_regs[5]; -}; - -static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) -{ - struct hifier_data *data = chip->model_data; - - oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | - OXYGEN_SPI_DATA_LENGTH_2 | - OXYGEN_SPI_CLOCK_160 | - (0 << OXYGEN_SPI_CODEC_SHIFT) | - OXYGEN_SPI_CEN_LATCH_CLOCK_HI, - AK4396_WRITE | (reg << 8) | value); - data->ak4396_regs[reg] = value; -} - -static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value) -{ - struct hifier_data *data = chip->model_data; - - if (value != data->ak4396_regs[reg]) - ak4396_write(chip, reg, value); -} - -static void hifier_registers_init(struct oxygen *chip) -{ - struct hifier_data *data = chip->model_data; - - ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); - ak4396_write(chip, AK4396_CONTROL_2, - data->ak4396_regs[AK4396_CONTROL_2]); - ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); - ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); - ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); -} - -static void hifier_init(struct oxygen *chip) -{ - struct hifier_data *data = chip->model_data; - - data->ak4396_regs[AK4396_CONTROL_2] = - AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; - hifier_registers_init(chip); - - snd_component_add(chip->card, "AK4396"); - snd_component_add(chip->card, "CS5340"); -} - -static void hifier_cleanup(struct oxygen *chip) -{ -} - -static void hifier_resume(struct oxygen *chip) -{ - hifier_registers_init(chip); -} - -static void set_ak4396_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) -{ - struct hifier_data *data = chip->model_data; - u8 value; - - value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK; - if (params_rate(params) <= 54000) - value |= AK4396_DFS_NORMAL; - else if (params_rate(params) <= 108000) - value |= AK4396_DFS_DOUBLE; - else - value |= AK4396_DFS_QUAD; - - msleep(1); /* wait for the new MCLK to become stable */ - - if (value != data->ak4396_regs[AK4396_CONTROL_2]) { - ak4396_write(chip, AK4396_CONTROL_1, - AK4396_DIF_24_MSB); - ak4396_write(chip, AK4396_CONTROL_2, value); - ak4396_write(chip, AK4396_CONTROL_1, - AK4396_DIF_24_MSB | AK4396_RSTN); - } -} - -static void update_ak4396_volume(struct oxygen *chip) -{ - ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]); - ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]); -} - -static void update_ak4396_mute(struct oxygen *chip) -{ - struct hifier_data *data = chip->model_data; - u8 value; - - value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE; - if (chip->dac_mute) - value |= AK4396_SMUTE; - ak4396_write_cached(chip, AK4396_CONTROL_2, value); -} - -static void set_cs5340_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) -{ -} - -static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); - -static const struct oxygen_model model_hifier = { - .shortname = "C-Media CMI8787", - .longname = "C-Media Oxygen HD Audio", - .chip = "CMI8788", - .init = hifier_init, - .cleanup = hifier_cleanup, - .resume = hifier_resume, - .get_i2s_mclk = oxygen_default_i2s_mclk, - .set_dac_params = set_ak4396_params, - .set_adc_params = set_cs5340_params, - .update_dac_volume = update_ak4396_volume, - .update_dac_mute = update_ak4396_mute, - .dac_tlv = ak4396_db_scale, - .model_data_size = sizeof(struct hifier_data), - .device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_1, - .dac_channels = 2, - .dac_volume_min = 0, - .dac_volume_max = 255, - .function_flags = OXYGEN_FUNCTION_SPI, - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, - .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, -}; - -static int __devinit get_hifier_model(struct oxygen *chip, - const struct pci_device_id *id) -{ - chip->model = model_hifier; - return 0; -} - -static int __devinit hifier_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) -{ - static int dev; - int err; - - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - ++dev; - return -ENOENT; - } - err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, - hifier_ids, get_hifier_model); - if (err >= 0) - ++dev; - return err; -} - -static struct pci_driver hifier_driver = { - .name = "CMI8787HiFier", - .id_table = hifier_ids, - .probe = hifier_probe, - .remove = __devexit_p(oxygen_pci_remove), -#ifdef CONFIG_PM - .suspend = oxygen_pci_suspend, - .resume = oxygen_pci_resume, -#endif -}; - -static int __init alsa_card_hifier_init(void) -{ - return pci_register_driver(&hifier_driver); -} - -static void __exit alsa_card_hifier_exit(void) -{ - pci_unregister_driver(&hifier_driver); -} - -module_init(alsa_card_hifier_init) -module_exit(alsa_card_hifier_exit) diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 98a8eb3c92f..dc47977beca 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -20,19 +20,25 @@ /* * CMI8788: * - * SPI 0 -> 1st AK4396 (front) - * SPI 1 -> 2nd AK4396 (surround) - * SPI 2 -> 3rd AK4396 (center/LFE) - * SPI 3 -> WM8785 - * SPI 4 -> 4th AK4396 (back) + * SPI 0 -> 1st AK4396 (front) + * SPI 1 -> 2nd AK4396 (surround) + * SPI 2 -> 3rd AK4396 (center/LFE) + * SPI 3 -> WM8785 + * SPI 4 -> 4th AK4396 (back) * - * GPIO 0 -> DFS0 of AK5385 - * GPIO 1 -> DFS1 of AK5385 - * GPIO 8 -> enable headphone amplifier on HT-Omega models + * GPIO 0 -> DFS0 of AK5385 + * GPIO 1 -> DFS1 of AK5385 + * GPIO 8 -> enable headphone amplifier on HT-Omega models * * CM9780: * - * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input + * LINE_OUT -> input of ADC + * + * AUX_IN <- aux + * CD_IN <- CD + * MIC_IN <- mic + * + * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input */ #include <linux/delay.h> @@ -41,6 +47,7 @@ #include <sound/ac97_codec.h> #include <sound/control.h> #include <sound/core.h> +#include <sound/info.h> #include <sound/initval.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -66,24 +73,35 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "enable card"); enum { - MODEL_CMEDIA_REF, /* C-Media's reference design */ - MODEL_MERIDIAN, /* AuzenTech X-Meridian */ - MODEL_CLARO, /* HT-Omega Claro */ - MODEL_CLARO_HALO, /* HT-Omega Claro halo */ + MODEL_CMEDIA_REF, + MODEL_MERIDIAN, + MODEL_CLARO, + MODEL_CLARO_HALO, + MODEL_FANTASIA, + MODEL_2CH_OUTPUT, }; static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { + /* C-Media's reference design */ { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, - { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, + /* Kuroutoshikou CMI8787-HG2PCI */ + { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_2CH_OUTPUT }, + /* TempoTec HiFier Fantasia */ + { OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_FANTASIA }, + /* TempoTec HiFier Serenade */ + { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_2CH_OUTPUT }, + /* AuzenTech X-Meridian */ { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, + /* HT-Omega Claro */ { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, + /* HT-Omega Claro halo */ { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO }, { } }; @@ -98,6 +116,7 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); #define GPIO_CLARO_HP 0x0100 struct generic_data { + unsigned int dacs; u8 ak4396_regs[4][5]; u16 wm8785_regs[3]; }; @@ -148,7 +167,7 @@ static void ak4396_registers_init(struct oxygen *chip) struct generic_data *data = chip->model_data; unsigned int i; - for (i = 0; i < 4; ++i) { + for (i = 0; i < data->dacs; ++i) { ak4396_write(chip, i, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); ak4396_write(chip, i, AK4396_CONTROL_2, @@ -166,6 +185,7 @@ static void ak4396_init(struct oxygen *chip) { struct generic_data *data = chip->model_data; + data->dacs = chip->model.dac_channels / 2; data->ak4396_regs[0][AK4396_CONTROL_2] = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; ak4396_registers_init(chip); @@ -232,6 +252,17 @@ static void claro_halo_init(struct oxygen *chip) claro_enable_hp(chip); } +static void fantasia_init(struct oxygen *chip) +{ + ak4396_init(chip); + snd_component_add(chip->card, "CS5340"); +} + +static void stereo_output_init(struct oxygen *chip) +{ + ak4396_init(chip); +} + static void generic_cleanup(struct oxygen *chip) { } @@ -268,6 +299,11 @@ static void claro_resume(struct oxygen *chip) claro_enable_hp(chip); } +static void stereo_resume(struct oxygen *chip) +{ + ak4396_registers_init(chip); +} + static void set_ak4396_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { @@ -286,7 +322,7 @@ static void set_ak4396_params(struct oxygen *chip, msleep(1); /* wait for the new MCLK to become stable */ if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) { - for (i = 0; i < 4; ++i) { + for (i = 0; i < data->dacs; ++i) { ak4396_write(chip, i, AK4396_CONTROL_1, AK4396_DIF_24_MSB); ak4396_write(chip, i, AK4396_CONTROL_2, value); @@ -298,9 +334,10 @@ static void set_ak4396_params(struct oxygen *chip, static void update_ak4396_volume(struct oxygen *chip) { + struct generic_data *data = chip->model_data; unsigned int i; - for (i = 0; i < 4; ++i) { + for (i = 0; i < data->dacs; ++i) { ak4396_write_cached(chip, i, AK4396_LCH_ATT, chip->dac_volume[i * 2]); ak4396_write_cached(chip, i, AK4396_RCH_ATT, @@ -317,7 +354,7 @@ static void update_ak4396_mute(struct oxygen *chip) value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE; if (chip->dac_mute) value |= AK4396_SMUTE; - for (i = 0; i < 4; ++i) + for (i = 0; i < data->dacs; ++i) ak4396_write_cached(chip, i, AK4396_CONTROL_2, value); } @@ -356,6 +393,10 @@ static void set_ak5385_params(struct oxygen *chip, value, GPIO_AK5385_DFS_MASK); } +static void set_no_params(struct oxygen *chip, struct snd_pcm_hw_params *params) +{ +} + static int rolloff_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { @@ -400,7 +441,7 @@ static int rolloff_put(struct snd_kcontrol *ctl, reg &= ~AK4396_SLOW; changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2]; if (changed) { - for (i = 0; i < 4; ++i) + for (i = 0; i < data->dacs; ++i) ak4396_write(chip, i, AK4396_CONTROL_2, reg); } mutex_unlock(&chip->mutex); @@ -484,6 +525,39 @@ static int generic_wm8785_mixer_init(struct oxygen *chip) return 0; } +static void dump_ak4396_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + struct generic_data *data = chip->model_data; + unsigned int dac, i; + + for (dac = 0; dac < data->dacs; ++dac) { + snd_iprintf(buffer, "\nAK4396 %u:", dac + 1); + for (i = 0; i < 5; ++i) + snd_iprintf(buffer, " %02x", data->ak4396_regs[dac][i]); + } + snd_iprintf(buffer, "\n"); +} + +static void dump_wm8785_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + struct generic_data *data = chip->model_data; + unsigned int i; + + snd_iprintf(buffer, "\nWM8785:"); + for (i = 0; i < 3; ++i) + snd_iprintf(buffer, " %03x", data->wm8785_regs[i]); + snd_iprintf(buffer, "\n"); +} + +static void dump_oxygen_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + dump_ak4396_registers(chip, buffer); + dump_wm8785_registers(chip, buffer); +} + static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); static const struct oxygen_model model_generic = { @@ -499,6 +573,7 @@ static const struct oxygen_model model_generic = { .set_adc_params = set_wm8785_params, .update_dac_volume = update_ak4396_volume, .update_dac_mute = update_ak4396_mute, + .dump_registers = dump_oxygen_registers, .dac_tlv = ak4396_db_scale, .model_data_size = sizeof(struct generic_data), .device_config = PLAYBACK_0_TO_I2S | @@ -527,6 +602,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip, chip->model.mixer_init = generic_mixer_init; chip->model.resume = meridian_resume; chip->model.set_adc_params = set_ak5385_params; + chip->model.dump_registers = dump_ak4396_registers; chip->model.device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | @@ -545,11 +621,30 @@ static int __devinit get_oxygen_model(struct oxygen *chip, chip->model.suspend = claro_suspend; chip->model.resume = claro_resume; chip->model.set_adc_params = set_ak5385_params; + chip->model.dump_registers = dump_ak4396_registers; chip->model.device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF; break; + case MODEL_FANTASIA: + case MODEL_2CH_OUTPUT: + chip->model.shortname = "C-Media CMI8787"; + chip->model.chip = "CMI8787"; + if (id->driver_data == MODEL_FANTASIA) + chip->model.init = fantasia_init; + else + chip->model.init = stereo_output_init; + chip->model.resume = stereo_resume; + chip->model.mixer_init = generic_mixer_init; + chip->model.set_adc_params = set_no_params; + chip->model.dump_registers = dump_ak4396_registers; + chip->model.device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF; + if (id->driver_data == MODEL_FANTASIA) + chip->model.device_config |= CAPTURE_0_FROM_I2S_1; + chip->model.dac_channels = 2; + break; } if (id->driver_data == MODEL_MERIDIAN || id->driver_data == MODEL_CLARO_HALO) { diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 7d5222caa0a..b8fbc15b89a 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -35,6 +35,7 @@ #define MIDI_OUTPUT 0x0800 #define MIDI_INPUT 0x1000 #define AC97_CD_INPUT 0x2000 +#define AC97_FMIC_SWITCH 0x4000 enum { CONTROL_SPDIF_PCM, @@ -65,6 +66,7 @@ struct snd_pcm_hardware; struct snd_pcm_hw_params; struct snd_kcontrol_new; struct snd_rawmidi; +struct snd_info_buffer; struct oxygen; struct oxygen_model { @@ -92,6 +94,8 @@ struct oxygen_model { void (*uart_input)(struct oxygen *chip); void (*ac97_switch)(struct oxygen *chip, unsigned int reg, unsigned int mute); + void (*dump_registers)(struct oxygen *chip, + struct snd_info_buffer *buffer); const unsigned int *dac_tlv; unsigned long private_data; size_t model_data_size; diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 969605fbcb7..c44c91e6fb1 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -202,7 +202,13 @@ static void oxygen_proc_read(struct snd_info_entry *entry, struct oxygen *chip = entry->private_data; int i, j; - snd_iprintf(buffer, "CMI8788\n\n"); + switch (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_PACKAGE_ID_MASK) { + case OXYGEN_PACKAGE_ID_8786: i = '6'; break; + case OXYGEN_PACKAGE_ID_8787: i = '7'; break; + case OXYGEN_PACKAGE_ID_8788: i = '8'; break; + default: i = '?'; break; + } + snd_iprintf(buffer, "CMI878%c:\n", i); for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) { snd_iprintf(buffer, "%02x:", i); for (j = 0; j < 0x10; ++j) @@ -212,7 +218,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, if (mutex_lock_interruptible(&chip->mutex) < 0) return; if (chip->has_ac97_0) { - snd_iprintf(buffer, "\nAC97\n"); + snd_iprintf(buffer, "\nAC97:\n"); for (i = 0; i < 0x80; i += 0x10) { snd_iprintf(buffer, "%02x:", i); for (j = 0; j < 0x10; j += 2) @@ -222,7 +228,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, } } if (chip->has_ac97_1) { - snd_iprintf(buffer, "\nAC97 2\n"); + snd_iprintf(buffer, "\nAC97 2:\n"); for (i = 0; i < 0x80; i += 0x10) { snd_iprintf(buffer, "%02x:", i); for (j = 0; j < 0x10; j += 2) @@ -232,13 +238,15 @@ static void oxygen_proc_read(struct snd_info_entry *entry, } } mutex_unlock(&chip->mutex); + if (chip->model.dump_registers) + chip->model.dump_registers(chip, buffer); } static void oxygen_proc_init(struct oxygen *chip) { struct snd_info_entry *entry; - if (!snd_card_proc_new(chip->card, "cmi8788", &entry)) + if (!snd_card_proc_new(chip->card, "oxygen", &entry)) snd_info_set_text_ops(entry, chip, oxygen_proc_read); } #else @@ -262,7 +270,7 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[]) */ subdevice = oxygen_read_eeprom(chip, 2); /* use default ID if EEPROM is missing */ - if (subdevice == 0xffff) + if (subdevice == 0xffff && oxygen_read_eeprom(chip, 1) == 0xffff) subdevice = 0x8788; /* * We use only the subsystem device ID for searching because it is diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 2849b36f5f7..605e84b9e1e 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -644,6 +644,51 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, return change; } +static int mic_fmic_source_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[] = { "Mic Jack", "Front Panel" }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + info->value.enumerated.item &= 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int mic_fmic_source_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + + mutex_lock(&chip->mutex); + value->value.enumerated.item[0] = + !!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC); + mutex_unlock(&chip->mutex); + return 0; +} + +static int mic_fmic_source_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 oldreg, newreg; + int change; + + mutex_lock(&chip->mutex); + oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK); + if (value->value.enumerated.item[0]) + newreg = oldreg | CM9780_FMIC2MIC; + else + newreg = oldreg & ~CM9780_FMIC2MIC; + change = newreg != oldreg; + if (change) + oxygen_write_ac97(chip, 0, CM9780_JACK, newreg); + mutex_unlock(&chip->mutex); + return change; +} + static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { @@ -908,6 +953,13 @@ static const struct snd_kcontrol_new ac97_controls[] = { AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0), AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Source Capture Enum", + .info = mic_fmic_source_info, + .get = mic_fmic_source_get, + .put = mic_fmic_source_put, + }, AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1), AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), @@ -972,6 +1024,9 @@ static int add_controls(struct oxygen *chip, if (!strcmp(template.name, "Stereo Upmixing") && chip->model.dac_channels == 2) continue; + if (!strcmp(template.name, "Mic Source Capture Enum") && + !(chip->model.device_config & AC97_FMIC_SWITCH)) + continue; if (!strncmp(template.name, "CD Capture ", 11) && !(chip->model.device_config & AC97_CD_INPUT)) continue; diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 814667442eb..60e4aa00c04 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -39,7 +39,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START, + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_32000 | @@ -65,7 +66,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START, + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_32000 | @@ -91,7 +93,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START, + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, @@ -530,7 +533,10 @@ static int oxygen_prepare(struct snd_pcm_substream *substream) oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); - chip->interrupt_mask |= channel_mask; + if (substream->runtime->no_period_wakeup) + chip->interrupt_mask &= ~channel_mask; + else + chip->interrupt_mask |= channel_mask; oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); spin_unlock_irq(&chip->reg_lock); return 0; diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h index b35343b0a9a..0434c207e81 100644 --- a/sound/pci/oxygen/xonar.h +++ b/sound/pci/oxygen/xonar.h @@ -24,6 +24,8 @@ void xonar_init_ext_power(struct oxygen *chip); void xonar_init_cs53x1(struct oxygen *chip); void xonar_set_cs53x1_params(struct oxygen *chip, struct snd_pcm_hw_params *params); + +#define XONAR_GPIO_BIT_INVERT (1 << 16) int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value); int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index aa27c31049a..de32895b317 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -22,29 +22,28 @@ * * CMI8788: * - * I²C <-> CS4398 (front) - * <-> CS4362A (surround, center/LFE, back) + * I²C <-> CS4398 (addr 1001111) (front) + * <-> CS4362A (addr 0011000) (surround, center/LFE, back) * - * GPI 0 <- external power present (DX only) + * GPI 0 <- external power present (DX only) * - * GPIO 0 -> enable output to speakers - * GPIO 1 -> enable front panel I/O - * GPIO 2 -> M0 of CS5361 - * GPIO 3 -> M1 of CS5361 - * GPIO 8 -> route input jack to line-in (0) or mic-in (1) + * GPIO 0 -> enable output to speakers + * GPIO 1 -> route output to front panel + * GPIO 2 -> M0 of CS5361 + * GPIO 3 -> M1 of CS5361 + * GPIO 6 -> ? + * GPIO 7 -> ? + * GPIO 8 -> route input jack to line-in (0) or mic-in (1) * - * CS4398: - * - * AD0 <- 1 - * AD1 <- 1 - * - * CS4362A: + * CM9780: * - * AD0 <- 0 + * LINE_OUT -> input of ADC * - * CM9780: + * AUX_IN <- aux + * MIC_IN <- mic + * FMIC_IN <- front mic * - * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input + * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input */ #include <linux/pci.h> @@ -63,6 +62,7 @@ #define GPI_EXT_POWER 0x01 #define GPIO_D1_OUTPUT_ENABLE 0x0001 #define GPIO_D1_FRONT_PANEL 0x0002 +#define GPIO_D1_MAGIC 0x00c0 #define GPIO_D1_INPUT_ROUTE 0x0100 #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ @@ -169,12 +169,12 @@ static void xonar_d1_init(struct oxygen *chip) cs43xx_registers_init(chip); oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); + GPIO_D1_FRONT_PANEL | + GPIO_D1_MAGIC | + GPIO_D1_INPUT_ROUTE); oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); - oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); - xonar_init_cs53x1(chip); xonar_enable_output(chip); @@ -284,7 +284,7 @@ static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed) static const struct snd_kcontrol_new front_panel_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Front Panel Switch", + .name = "Front Panel Playback Switch", .info = snd_ctl_boolean_mono_info, .get = xonar_gpio_bit_switch_get, .put = xonar_gpio_bit_switch_put, @@ -380,6 +380,30 @@ static int xonar_d1_mixer_init(struct oxygen *chip) return 0; } +static void dump_cs4362a_registers(struct xonar_cs43xx *data, + struct snd_info_buffer *buffer) +{ + unsigned int i; + + snd_iprintf(buffer, "\nCS4362A:"); + for (i = 1; i <= 14; ++i) + snd_iprintf(buffer, " %02x", data->cs4362a_regs[i]); + snd_iprintf(buffer, "\n"); +} + +static void dump_d1_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + struct xonar_cs43xx *data = chip->model_data; + unsigned int i; + + snd_iprintf(buffer, "\nCS4398: 7?"); + for (i = 2; i <= 8; ++i) + snd_iprintf(buffer, " %02x", data->cs4398_regs[i]); + snd_iprintf(buffer, "\n"); + dump_cs4362a_registers(data, buffer); +} + static const struct oxygen_model model_xonar_d1 = { .longname = "Asus Virtuoso 100", .chip = "AV200", @@ -395,11 +419,13 @@ static const struct oxygen_model model_xonar_d1 = { .update_dac_mute = update_cs43xx_mute, .update_center_lfe_mix = update_cs43xx_center_lfe_mix, .ac97_switch = xonar_d1_line_mic_ac97_switch, + .dump_registers = dump_d1_registers, .dac_tlv = cs4362a_db_scale, .model_data_size = sizeof(struct xonar_cs43xx), .device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2, + CAPTURE_0_FROM_I2S_2 | + AC97_FMIC_SWITCH, .dac_channels = 8, .dac_volume_min = 127 - 60, .dac_volume_max = 127, diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c index b3ff7131665..0ebe7f5916f 100644 --- a/sound/pci/oxygen/xonar_lib.c +++ b/sound/pci/oxygen/xonar_lib.c @@ -104,9 +104,10 @@ int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, { struct oxygen *chip = ctl->private_data; u16 bit = ctl->private_value; + bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; value->value.integer.value[0] = - !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit); + !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert; return 0; } @@ -115,12 +116,13 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, { struct oxygen *chip = ctl->private_data; u16 bit = ctl->private_value; + bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; u16 old_bits, new_bits; int changed; spin_lock_irq(&chip->reg_lock); old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); - if (value->value.integer.value[0]) + if (!!value->value.integer.value[0] ^ invert) new_bits = old_bits | bit; else new_bits = old_bits & ~bit; diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index d491fd6c0be..bf357c01afd 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -22,20 +22,26 @@ * * CMI8788: * - * SPI 0 -> 1st PCM1796 (front) - * SPI 1 -> 2nd PCM1796 (surround) - * SPI 2 -> 3rd PCM1796 (center/LFE) - * SPI 4 -> 4th PCM1796 (back) + * SPI 0 -> 1st PCM1796 (front) + * SPI 1 -> 2nd PCM1796 (surround) + * SPI 2 -> 3rd PCM1796 (center/LFE) + * SPI 4 -> 4th PCM1796 (back) * - * GPIO 2 -> M0 of CS5381 - * GPIO 3 -> M1 of CS5381 - * GPIO 5 <- external power present (D2X only) - * GPIO 7 -> ALT - * GPIO 8 -> enable output to speakers + * GPIO 2 -> M0 of CS5381 + * GPIO 3 -> M1 of CS5381 + * GPIO 5 <- external power present (D2X only) + * GPIO 7 -> ALT + * GPIO 8 -> enable output to speakers * * CM9780: * - * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input + * LINE_OUT -> input of ADC + * + * AUX_IN <- aux + * VIDEO_IN <- CD + * FMIC_IN <- mic + * + * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input */ /* @@ -44,52 +50,53 @@ * * CMI8788: * - * I²C <-> PCM1796 (front) + * I²C <-> PCM1796 (addr 1001100) (front) * - * GPI 0 <- external power present + * GPI 0 <- external power present * - * GPIO 0 -> enable output to speakers - * GPIO 2 -> M0 of CS5381 - * GPIO 3 -> M1 of CS5381 - * GPIO 8 -> route input jack to line-in (0) or mic-in (1) + * GPIO 0 -> enable HDMI (0) or speaker (1) output + * GPIO 2 -> M0 of CS5381 + * GPIO 3 -> M1 of CS5381 + * GPIO 4 <- daughterboard detection + * GPIO 5 <- daughterboard detection + * GPIO 6 -> ? + * GPIO 7 -> ? + * GPIO 8 -> route input jack to line-in (0) or mic-in (1) * - * TXD -> HDMI controller - * RXD <- HDMI controller - * - * PCM1796 front: AD1,0 <- 0,0 + * UART <-> HDMI controller * * CM9780: * - * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input + * LINE_OUT -> input of ADC + * + * AUX_IN <- aux + * CD_IN <- CD + * MIC_IN <- mic + * + * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input * * no daughterboard * ---------------- * - * GPIO 4 <- 1 + * GPIO 4 <- 1 * * H6 daughterboard * ---------------- * - * GPIO 4 <- 0 - * GPIO 5 <- 0 + * GPIO 4 <- 0 + * GPIO 5 <- 0 * - * I²C <-> PCM1796 (surround) - * <-> PCM1796 (center/LFE) - * <-> PCM1796 (back) - * - * PCM1796 surround: AD1,0 <- 0,1 - * PCM1796 center/LFE: AD1,0 <- 1,0 - * PCM1796 back: AD1,0 <- 1,1 + * I²C <-> PCM1796 (addr 1001101) (surround) + * <-> PCM1796 (addr 1001110) (center/LFE) + * <-> PCM1796 (addr 1001111) (back) * * unknown daughterboard * --------------------- * - * GPIO 4 <- 0 - * GPIO 5 <- 1 - * - * I²C <-> CS4362A (surround, center/LFE, back) + * GPIO 4 <- 0 + * GPIO 5 <- 1 * - * CS4362A: AD0 <- 0 + * I²C <-> CS4362A (addr 0011000) (surround, center/LFE, back) */ /* @@ -98,32 +105,35 @@ * * CMI8788: * - * I²C <-> PCM1792A - * <-> CS2000 (ST only) + * I²C <-> PCM1792A (addr 1001100) + * <-> CS2000 (addr 1001110) (ST only) * - * ADC1 MCLK -> REF_CLK of CS2000 (ST only) + * ADC1 MCLK -> REF_CLK of CS2000 (ST only) * - * GPI 0 <- external power present (STX only) + * GPI 0 <- external power present (STX only) * - * GPIO 0 -> enable output to speakers - * GPIO 1 -> route HP to front panel (0) or rear jack (1) - * GPIO 2 -> M0 of CS5381 - * GPIO 3 -> M1 of CS5381 - * GPIO 7 -> route output to speaker jacks (0) or HP (1) - * GPIO 8 -> route input jack to line-in (0) or mic-in (1) + * GPIO 0 -> enable output to speakers + * GPIO 1 -> route HP to front panel (0) or rear jack (1) + * GPIO 2 -> M0 of CS5381 + * GPIO 3 -> M1 of CS5381 + * GPIO 4 <- daughterboard detection + * GPIO 5 <- daughterboard detection + * GPIO 6 -> ? + * GPIO 7 -> route output to speaker jacks (0) or HP (1) + * GPIO 8 -> route input jack to line-in (0) or mic-in (1) * * PCM1792A: * - * AD1,0 <- 0,0 - * SCK <- CLK_OUT of CS2000 (ST only) + * SCK <- CLK_OUT of CS2000 (ST only) * - * CS2000: + * CM9780: * - * AD0 <- 0 + * LINE_OUT -> input of ADC * - * CM9780: + * AUX_IN <- aux + * MIC_IN <- mic * - * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input + * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input * * H6 daughterboard * ---------------- @@ -133,15 +143,39 @@ */ /* - * Xonar HDAV1.3 Slim - * ------------------ + * Xonar Xense + * ----------- * * CMI8788: * - * GPIO 1 -> enable output + * I²C <-> PCM1796 (addr 1001100) (front) + * <-> CS4362A (addr 0011000) (surround, center/LFE, back) + * <-> CS2000 (addr 1001110) + * + * ADC1 MCLK -> REF_CLK of CS2000 * - * TXD -> HDMI controller - * RXD <- HDMI controller + * GPI 0 <- external power present + * + * GPIO 0 -> enable output + * GPIO 1 -> route HP to front panel (0) or rear jack (1) + * GPIO 2 -> M0 of CS5381 + * GPIO 3 -> M1 of CS5381 + * GPIO 4 -> enable output + * GPIO 5 -> enable output + * GPIO 6 -> ? + * GPIO 7 -> route output to HP (0) or speaker (1) + * GPIO 8 -> route input jack to mic-in (0) or line-in (1) + * + * CM9780: + * + * LINE_OUT -> input of ADC + * + * AUX_IN <- aux + * VIDEO_IN <- ? + * FMIC_IN <- mic + * + * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input + * GPO 1 -> route mic-in from input jack (0) or front panel header (1) */ #include <linux/pci.h> @@ -150,6 +184,7 @@ #include <sound/ac97_codec.h> #include <sound/control.h> #include <sound/core.h> +#include <sound/info.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/tlv.h> @@ -167,12 +202,14 @@ #define GPIO_INPUT_ROUTE 0x0100 #define GPIO_HDAV_OUTPUT_ENABLE 0x0001 +#define GPIO_HDAV_MAGIC 0x00c0 #define GPIO_DB_MASK 0x0030 #define GPIO_DB_H6 0x0000 #define GPIO_ST_OUTPUT_ENABLE 0x0001 #define GPIO_ST_HP_REAR 0x0002 +#define GPIO_ST_MAGIC 0x0040 #define GPIO_ST_HP 0x0080 #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ @@ -190,7 +227,7 @@ struct xonar_pcm179x { bool hp_active; s8 hp_gain_offset; bool has_cs2000; - u8 cs2000_fun_cfg_1; + u8 cs2000_regs[0x1f]; }; struct xonar_hdav { @@ -249,16 +286,14 @@ static void cs2000_write(struct oxygen *chip, u8 reg, u8 value) struct xonar_pcm179x *data = chip->model_data; oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); - if (reg == CS2000_FUN_CFG_1) - data->cs2000_fun_cfg_1 = value; + data->cs2000_regs[reg] = value; } static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value) { struct xonar_pcm179x *data = chip->model_data; - if (reg != CS2000_FUN_CFG_1 || - value != data->cs2000_fun_cfg_1) + if (value != data->cs2000_regs[reg]) cs2000_write(chip, reg, value); } @@ -350,7 +385,8 @@ static void xonar_hdav_init(struct oxygen *chip) pcm1796_init(chip); - oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE); + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_HDAV_MAGIC | GPIO_INPUT_ROUTE); oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE); xonar_init_cs53x1(chip); @@ -381,7 +417,8 @@ static void xonar_st_init_common(struct oxygen *chip) pcm1796_init(chip); oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); + GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | + GPIO_ST_MAGIC | GPIO_ST_HP); oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); @@ -410,7 +447,8 @@ static void cs2000_registers_init(struct oxygen *chip) cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10); cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00); cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00); - cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1); + cs2000_write(chip, CS2000_FUN_CFG_1, + data->cs2000_regs[CS2000_FUN_CFG_1]); cs2000_write(chip, CS2000_FUN_CFG_2, 0); cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2); } @@ -421,7 +459,7 @@ static void xonar_st_init(struct oxygen *chip) data->generic.anti_pop_delay = 100; data->has_cs2000 = 1; - data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_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 | @@ -772,6 +810,15 @@ static const struct snd_kcontrol_new os_128_control = { .put = os_128_put, }; +static const struct snd_kcontrol_new hdav_hdmi_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HDMI Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = xonar_gpio_bit_switch_get, + .put = xonar_gpio_bit_switch_put, + .private_value = GPIO_HDAV_OUTPUT_ENABLE | XONAR_GPIO_BIT_INVERT, +}; + static int st_output_switch_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { @@ -956,7 +1003,15 @@ static int xonar_d2_mixer_init(struct oxygen *chip) static int xonar_hdav_mixer_init(struct oxygen *chip) { - return add_pcm1796_controls(chip); + int err; + + err = snd_ctl_add(chip->card, snd_ctl_new1(&hdav_hdmi_control, chip)); + if (err < 0) + return err; + err = add_pcm1796_controls(chip); + if (err < 0) + return err; + return 0; } static int xonar_st_mixer_init(struct oxygen *chip) @@ -976,6 +1031,45 @@ static int xonar_st_mixer_init(struct oxygen *chip) return 0; } +static void dump_pcm1796_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + struct xonar_pcm179x *data = chip->model_data; + unsigned int dac, i; + + for (dac = 0; dac < data->dacs; ++dac) { + snd_iprintf(buffer, "\nPCM1796 %u:", dac + 1); + for (i = 0; i < 5; ++i) + snd_iprintf(buffer, " %02x", + data->pcm1796_regs[dac][i]); + } + snd_iprintf(buffer, "\n"); +} + +static void dump_cs2000_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + + if (data->has_cs2000) { + snd_iprintf(buffer, "\nCS2000:\n00: "); + for (i = 1; i < 0x10; ++i) + snd_iprintf(buffer, " %02x", data->cs2000_regs[i]); + snd_iprintf(buffer, "\n10:"); + for (i = 0x10; i < 0x1f; ++i) + snd_iprintf(buffer, " %02x", data->cs2000_regs[i]); + snd_iprintf(buffer, "\n"); + } +} + +static void dump_st_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + dump_pcm1796_registers(chip, buffer); + dump_cs2000_registers(chip, buffer); +} + static const struct oxygen_model model_xonar_d2 = { .longname = "Asus Virtuoso 200", .chip = "AV200", @@ -990,6 +1084,7 @@ static const struct oxygen_model model_xonar_d2 = { .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, .update_dac_mute = update_pcm1796_mute, + .dump_registers = dump_pcm1796_registers, .dac_tlv = pcm1796_db_scale, .model_data_size = sizeof(struct xonar_pcm179x), .device_config = PLAYBACK_0_TO_I2S | @@ -1025,6 +1120,7 @@ static const struct oxygen_model model_xonar_hdav = { .update_dac_mute = update_pcm1796_mute, .uart_input = xonar_hdmi_uart_input, .ac97_switch = xonar_line_mic_ac97_switch, + .dump_registers = dump_pcm1796_registers, .dac_tlv = pcm1796_db_scale, .model_data_size = sizeof(struct xonar_hdav), .device_config = PLAYBACK_0_TO_I2S | @@ -1054,11 +1150,13 @@ static const struct oxygen_model model_xonar_st = { .update_dac_volume = update_pcm1796_volume, .update_dac_mute = update_pcm1796_mute, .ac97_switch = xonar_line_mic_ac97_switch, + .dump_registers = dump_st_registers, .dac_tlv = pcm1796_db_scale, .model_data_size = sizeof(struct xonar_pcm179x), .device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2, + CAPTURE_0_FROM_I2S_2 | + AC97_FMIC_SWITCH, .dac_channels = 2, .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 200f7601276..1705d1e9311 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -22,26 +22,48 @@ * * CMI8788: * - * SPI 0 -> WM8766 (surround, center/LFE, back) - * SPI 1 -> WM8776 (front, input) + * SPI 0 -> WM8766 (surround, center/LFE, back) + * SPI 1 -> WM8776 (front, input) * - * GPIO 4 <- headphone detect, 0 = plugged - * GPIO 6 -> route input jack to mic-in (0) or line-in (1) - * GPIO 7 -> enable output to front L/R speaker channels - * GPIO 8 -> enable output to other speaker channels and front panel headphone + * GPIO 4 <- headphone detect, 0 = plugged + * GPIO 6 -> route input jack to mic-in (0) or line-in (1) + * GPIO 7 -> enable output to front L/R speaker channels + * GPIO 8 -> enable output to other speaker channels and front panel headphone * - * WM8766: + * WM8776: * - * input 1 <- line - * input 2 <- mic - * input 3 <- front mic - * input 4 <- aux + * input 1 <- line + * input 2 <- mic + * input 3 <- front mic + * input 4 <- aux + */ + +/* + * Xonar HDAV1.3 Slim + * ------------------ + * + * CMI8788: + * + * I²C <-> WM8776 (addr 0011010) + * + * GPIO 0 -> disable HDMI output + * GPIO 1 -> enable HP output + * GPIO 6 -> firmware EEPROM I²C clock + * GPIO 7 <-> firmware EEPROM I²C data + * + * UART <-> HDMI controller + * + * WM8776: + * + * input 1 <- mic + * input 2 <- aux */ #include <linux/pci.h> #include <linux/delay.h> #include <sound/control.h> #include <sound/core.h> +#include <sound/info.h> #include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -1062,6 +1084,34 @@ static int xonar_ds_mixer_init(struct oxygen *chip) return 0; } +static void dump_wm8776_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + struct xonar_wm87x6 *data = chip->model_data; + unsigned int i; + + snd_iprintf(buffer, "\nWM8776:\n00:"); + for (i = 0; i < 0x10; ++i) + snd_iprintf(buffer, " %03x", data->wm8776_regs[i]); + snd_iprintf(buffer, "\n10:"); + for (i = 0x10; i < 0x17; ++i) + snd_iprintf(buffer, " %03x", data->wm8776_regs[i]); + snd_iprintf(buffer, "\n"); +} + +static void dump_wm87x6_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + struct xonar_wm87x6 *data = chip->model_data; + unsigned int i; + + dump_wm8776_registers(chip, buffer); + snd_iprintf(buffer, "\nWM8766:\n00:"); + for (i = 0; i < 0x10; ++i) + snd_iprintf(buffer, " %03x", data->wm8766_regs[i]); + snd_iprintf(buffer, "\n"); +} + static const struct oxygen_model model_xonar_ds = { .shortname = "Xonar DS", .longname = "Asus Virtuoso 66", @@ -1079,6 +1129,7 @@ static const struct oxygen_model model_xonar_ds = { .update_dac_mute = update_wm87x6_mute, .update_center_lfe_mix = update_wm8766_center_lfe_mix, .gpio_changed = xonar_ds_gpio_changed, + .dump_registers = dump_wm87x6_registers, .dac_tlv = wm87x6_dac_db_scale, .model_data_size = sizeof(struct xonar_wm87x6), .device_config = PLAYBACK_0_TO_I2S | |