From 45c1de8e20cec40b6846def0aeca09cb1bfb839b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 2 Nov 2010 17:08:37 +0100 Subject: ALSA: oxygen: merge HiFier driver into snd-oxygen The snd-hifier driver contains more duplicated code than model-specific code, so it does not make sense for it to be a separate driver. Handling the two-channel output restriction can be easily done in the generic driver. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 98a8eb3c92f7..5e258b26f044 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -70,6 +70,7 @@ enum { MODEL_MERIDIAN, /* AuzenTech X-Meridian */ MODEL_CLARO, /* HT-Omega Claro */ MODEL_CLARO_HALO, /* HT-Omega Claro halo */ + MODEL_HIFIER, /* TempoTec HiFier Fantasia */ }; static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { @@ -81,6 +82,8 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { 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(0x14c3, 0x1710), .driver_data = MODEL_HIFIER }, + { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_HIFIER }, { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, @@ -98,6 +101,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 +152,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 +170,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 +237,12 @@ static void claro_halo_init(struct oxygen *chip) claro_enable_hp(chip); } +static void hifier_init(struct oxygen *chip) +{ + ak4396_init(chip); + snd_component_add(chip->card, "CS5340"); +} + static void generic_cleanup(struct oxygen *chip) { } @@ -268,6 +279,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 +302,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 +314,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 +334,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 +373,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 +421,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); @@ -550,6 +571,18 @@ static int __devinit get_oxygen_model(struct oxygen *chip, CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF; break; + case MODEL_HIFIER: + chip->model.shortname = "C-Media CMI8787"; + chip->model.chip = "CMI8787"; + chip->model.init = hifier_init; + chip->model.resume = stereo_resume; + chip->model.mixer_init = generic_mixer_init; + chip->model.set_adc_params = set_no_params; + chip->model.device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_1; + chip->model.dac_channels = 2; + break; } if (id->driver_data == MODEL_MERIDIAN || id->driver_data == MODEL_CLARO_HALO) { -- cgit v1.2.3 From 31f86bacfc9c8f6a3f25fa991c1f373374a9f25b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 2 Nov 2010 17:18:23 +0100 Subject: ALSA: oxygen: add Kuroutoshikou CMI8787-HG2PCI support Add support for the Kuroutoshikou CMI8787-HG2PCI sound card. [replaced non-latin letters in the patch by tiwai] Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/Kconfig | 1 + sound/pci/oxygen/oxygen.c | 19 +++++++++++++++---- sound/pci/oxygen/oxygen_lib.c | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index f1a1787e71e5..fdd388ded62a 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1531,6 +1531,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * Club3D Theatron DTS * HT-Omega Claro (plus) * HT-Omega Claro halo (XT) + * Kuroutoshikou CMI8787-HG2PCI * Razer Barracuda AC-1 * Sondigo Inferno * TempoTec HiFier Fantasia diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index dfe406de9935..f7139d09cbbe 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -222,6 +222,7 @@ config SND_OXYGEN * Club3D Theatron DTS * HT-Omega Claro (plus) * HT-Omega Claro halo (XT) + * Kuroutoshikou CMI8787-HG2PCI * Razer Barracuda AC-1 * Sondigo Inferno * TempoTec/MediaTek HiFier Fantasia diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 5e258b26f044..dd0f3f478999 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -71,6 +71,7 @@ enum { MODEL_CLARO, /* HT-Omega Claro */ MODEL_CLARO_HALO, /* HT-Omega Claro halo */ MODEL_HIFIER, /* TempoTec HiFier Fantasia */ + MODEL_HG2PCI, /* Kuroutoshikou CMI8787-HG2PCI */ }; static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { @@ -80,7 +81,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { 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(0x13f6, 0xffff), .driver_data = MODEL_HG2PCI }, { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_HIFIER }, { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_HIFIER }, @@ -243,6 +244,11 @@ static void hifier_init(struct oxygen *chip) snd_component_add(chip->card, "CS5340"); } +static void hg2pci_init(struct oxygen *chip) +{ + ak4396_init(chip); +} + static void generic_cleanup(struct oxygen *chip) { } @@ -572,15 +578,20 @@ static int __devinit get_oxygen_model(struct oxygen *chip, CAPTURE_1_FROM_SPDIF; break; case MODEL_HIFIER: + case MODEL_HG2PCI: chip->model.shortname = "C-Media CMI8787"; chip->model.chip = "CMI8787"; - chip->model.init = hifier_init; + if (id->driver_data == MODEL_HIFIER) + chip->model.init = hifier_init; + else + chip->model.init = hg2pci_init; chip->model.resume = stereo_resume; chip->model.mixer_init = generic_mixer_init; chip->model.set_adc_params = set_no_params; chip->model.device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_1; + PLAYBACK_1_TO_SPDIF; + if (id->driver_data == MODEL_HIFIER) + chip->model.device_config |= CAPTURE_0_FROM_I2S_1; chip->model.dac_channels = 2; break; } diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index e5ebe56fb0c5..2e6579962217 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -262,7 +262,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 -- cgit v1.2.3 From 18f24839f18f1934c1e37e86ce8f3fecbb0328c9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 3 Nov 2010 11:36:33 +0100 Subject: ALSA: oxygen: reorganize PCI IDs Sort the PCI IDs so that they make logical sense. Also move the card name comments into this list because the model symbols should be (more) self-explanationary. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index dd0f3f478999..13f39e58f3de 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -66,28 +66,34 @@ 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_HIFIER, /* TempoTec HiFier Fantasia */ - MODEL_HG2PCI, /* Kuroutoshikou CMI8787-HG2PCI */ + MODEL_CMEDIA_REF, + MODEL_MERIDIAN, + MODEL_CLARO, + MODEL_CLARO_HALO, + MODEL_HIFIER, + MODEL_HG2PCI, }; 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_HG2PCI }, { 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_HG2PCI }, + /* TempoTec HiFier Fantasia */ { OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_HIFIER }, { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_HIFIER }, - { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, + /* 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 }, { } }; -- cgit v1.2.3 From 2146dcfd15ad55cfdd18b45e1e6601d6a86f0cbe Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 3 Nov 2010 12:26:35 +0100 Subject: ALSA: oxygen: add HiFier Serenade support Add support for the TempoTec/MediaTek HiFier Serenade sound card. The PCI ID was already there, but the driver handled it like the Fantasia model, which resulted in a dummy recording device. As a stereo output-only card, this model is to be handled exactly like the HG2PCI. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/Kconfig | 1 + sound/pci/oxygen/oxygen.c | 27 +++++++++++++------------ 3 files changed, 16 insertions(+), 13 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index fdd388ded62a..7124340038ea 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1535,6 +1535,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * Razer Barracuda AC-1 * Sondigo Inferno * TempoTec HiFier Fantasia + * TempoTec HiFier Serenade This module supports autoprobe and multiple cards. diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index f7139d09cbbe..5add96bdf172 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -226,6 +226,7 @@ config SND_OXYGEN * Razer Barracuda AC-1 * Sondigo Inferno * TempoTec/MediaTek HiFier Fantasia + * TempoTec/MediaTek HiFier Serenade To compile this driver as a module, choose M here: the module will be called snd-oxygen. diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 13f39e58f3de..ea8fffefad9f 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -70,8 +70,8 @@ enum { MODEL_MERIDIAN, MODEL_CLARO, MODEL_CLARO_HALO, - MODEL_HIFIER, - MODEL_HG2PCI, + MODEL_FANTASIA, + MODEL_2CH_OUTPUT, }; static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { @@ -85,10 +85,11 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { 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_HG2PCI }, + { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_2CH_OUTPUT }, /* TempoTec HiFier Fantasia */ - { OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_HIFIER }, - { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_HIFIER }, + { 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 */ @@ -244,13 +245,13 @@ static void claro_halo_init(struct oxygen *chip) claro_enable_hp(chip); } -static void hifier_init(struct oxygen *chip) +static void fantasia_init(struct oxygen *chip) { ak4396_init(chip); snd_component_add(chip->card, "CS5340"); } -static void hg2pci_init(struct oxygen *chip) +static void stereo_output_init(struct oxygen *chip) { ak4396_init(chip); } @@ -583,20 +584,20 @@ static int __devinit get_oxygen_model(struct oxygen *chip, CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF; break; - case MODEL_HIFIER: - case MODEL_HG2PCI: + case MODEL_FANTASIA: + case MODEL_2CH_OUTPUT: chip->model.shortname = "C-Media CMI8787"; chip->model.chip = "CMI8787"; - if (id->driver_data == MODEL_HIFIER) - chip->model.init = hifier_init; + if (id->driver_data == MODEL_FANTASIA) + chip->model.init = fantasia_init; else - chip->model.init = hg2pci_init; + 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.device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF; - if (id->driver_data == MODEL_HIFIER) + if (id->driver_data == MODEL_FANTASIA) chip->model.device_config |= CAPTURE_0_FROM_I2S_1; chip->model.dac_channels = 2; break; -- cgit v1.2.3 From 9719fcaa6a82be59a2d7767725e5cd8233c6a387 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 2 Dec 2010 11:41:10 +0100 Subject: ALSA: oxygen: allow to dump codec registers To help with debugging, add the registers of the model-specific codecs to the controller and AC97 register dump in the proc file. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 38 +++++++++++++++++++++++++++ sound/pci/oxygen/oxygen.h | 3 +++ sound/pci/oxygen/oxygen_lib.c | 10 ++++--- sound/pci/oxygen/xonar_cs43xx.c | 25 ++++++++++++++++++ sound/pci/oxygen/xonar_pcm179x.c | 56 +++++++++++++++++++++++++++++++++++----- sound/pci/oxygen/xonar_wm87x6.c | 30 +++++++++++++++++++++ 6 files changed, 151 insertions(+), 11 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index ea8fffefad9f..a58e448fc1bf 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -518,6 +519,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 = { @@ -533,6 +567,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 | @@ -561,6 +596,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 | @@ -579,6 +615,7 @@ 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 | @@ -595,6 +632,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip, 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) diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index cf9054ecb97b..b8fbc15b89a3 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -66,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 { @@ -93,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 2e6579962217..e581e7ab216c 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -202,7 +202,7 @@ 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"); + snd_iprintf(buffer, "CMI8788:\n"); for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) { snd_iprintf(buffer, "%02x:", i); for (j = 0; j < 0x10; ++j) @@ -212,7 +212,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 +222,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 +232,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 diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 501fe45bbdce..092addb15e13 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -381,6 +381,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", @@ -396,6 +420,7 @@ 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 | diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 5193d73a916d..dc69fddf2e6e 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -150,6 +150,7 @@ #include #include #include +#include #include #include #include @@ -192,7 +193,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 { @@ -251,16 +252,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); } @@ -414,7 +413,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); } @@ -425,7 +425,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 | @@ -997,6 +997,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", @@ -1011,6 +1050,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 | @@ -1046,6 +1086,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 | @@ -1075,6 +1116,7 @@ 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 | diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 200f7601276f..2b5e69b64708 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1062,6 +1063,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 +1108,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 | -- cgit v1.2.3 From de664936930dae5469170f7eed24bcff7e91ef82 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 2 Dec 2010 11:42:48 +0100 Subject: ALSA: oxygen: update hardware comments Reformat and update the comments that describe the hardware connections on the various models. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 24 ++++--- sound/pci/oxygen/xonar_cs43xx.c | 33 +++++---- sound/pci/oxygen/xonar_pcm179x.c | 148 ++++++++++++++++++++++++--------------- sound/pci/oxygen/xonar_wm87x6.c | 43 +++++++++--- 4 files changed, 154 insertions(+), 94 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index a58e448fc1bf..dc47977becae 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 diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 092addb15e13..de32895b3172 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 -> route output to front panel - * 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 diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index dc69fddf2e6e..bf357c01afd2 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) - * - * GPI 0 <- external power present + * I²C <-> PCM1796 (addr 1001100) (front) * - * 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) + * GPI 0 <- external power present * - * TXD -> HDMI controller - * RXD <- HDMI controller + * 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) * - * 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 - * - * I²C <-> PCM1796 (surround) - * <-> PCM1796 (center/LFE) - * <-> PCM1796 (back) + * GPIO 4 <- 0 + * GPIO 5 <- 0 * - * 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 + * + * 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 * - * TXD -> HDMI controller - * RXD <- HDMI controller + * 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 diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 2b5e69b64708..1705d1e93115 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -22,20 +22,41 @@ * * 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 -- cgit v1.2.3 From 1f4d7be7293aecd5f8469a46f606f62f0f05d84c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 15:59:38 +0100 Subject: ALSA: oxygen: allow different number of PCM and mixer channels For cards like the Xonar HDAV1.3, differentiate between the number of PCM channels that can be played and the number of channels whose volume can be adjusted. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 8 +++++--- sound/pci/oxygen/oxygen.h | 3 ++- sound/pci/oxygen/oxygen_mixer.c | 8 ++++---- sound/pci/oxygen/oxygen_pcm.c | 2 +- sound/pci/oxygen/xonar_cs43xx.c | 3 ++- sound/pci/oxygen/xonar_pcm179x.c | 13 +++++++++---- sound/pci/oxygen/xonar_wm87x6.c | 3 ++- 7 files changed, 25 insertions(+), 15 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index dc47977becae..fe7ed4fc9f46 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -185,7 +185,7 @@ static void ak4396_init(struct oxygen *chip) { struct generic_data *data = chip->model_data; - data->dacs = chip->model.dac_channels / 2; + data->dacs = chip->model.dac_channels_pcm / 2; data->ak4396_regs[0][AK4396_CONTROL_2] = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; ak4396_registers_init(chip); @@ -583,7 +583,8 @@ static const struct oxygen_model model_generic = { CAPTURE_1_FROM_SPDIF | CAPTURE_2_FROM_AC97_1 | AC97_CD_INPUT, - .dac_channels = 8, + .dac_channels_pcm = 8, + .dac_channels_mixer = 8, .dac_volume_min = 0, .dac_volume_max = 255, .function_flags = OXYGEN_FUNCTION_SPI | @@ -643,7 +644,8 @@ static int __devinit get_oxygen_model(struct oxygen *chip, PLAYBACK_1_TO_SPDIF; if (id->driver_data == MODEL_FANTASIA) chip->model.device_config |= CAPTURE_0_FROM_I2S_1; - chip->model.dac_channels = 2; + chip->model.dac_channels_pcm = 2; + chip->model.dac_channels_mixer = 2; break; } if (id->driver_data == MODEL_MERIDIAN || diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index b8fbc15b89a3..3d9535c2debb 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -100,7 +100,8 @@ struct oxygen_model { unsigned long private_data; size_t model_data_size; unsigned int device_config; - u8 dac_channels; + u8 dac_channels_pcm; + u8 dac_channels_mixer; u8 dac_volume_min; u8 dac_volume_max; u8 misc_flags; diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 605e84b9e1ec..242c1cac69b8 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -31,7 +31,7 @@ static int dac_volume_info(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = chip->model.dac_channels; + info->count = chip->model.dac_channels_mixer; info->value.integer.min = chip->model.dac_volume_min; info->value.integer.max = chip->model.dac_volume_max; return 0; @@ -44,7 +44,7 @@ static int dac_volume_get(struct snd_kcontrol *ctl, unsigned int i; mutex_lock(&chip->mutex); - for (i = 0; i < chip->model.dac_channels; ++i) + for (i = 0; i < chip->model.dac_channels_mixer; ++i) value->value.integer.value[i] = chip->dac_volume[i]; mutex_unlock(&chip->mutex); return 0; @@ -59,7 +59,7 @@ static int dac_volume_put(struct snd_kcontrol *ctl, changed = 0; mutex_lock(&chip->mutex); - for (i = 0; i < chip->model.dac_channels; ++i) + for (i = 0; i < chip->model.dac_channels_mixer; ++i) if (value->value.integer.value[i] != chip->dac_volume[i]) { chip->dac_volume[i] = value->value.integer.value[i]; changed = 1; @@ -1022,7 +1022,7 @@ static int add_controls(struct oxygen *chip, continue; } if (!strcmp(template.name, "Stereo Upmixing") && - chip->model.dac_channels == 2) + chip->model.dac_channels_pcm == 2) continue; if (!strcmp(template.name, "Mic Source Capture Enum") && !(chip->model.device_config & AC97_FMIC_SWITCH)) diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 60e4aa00c042..dc3c68f76df4 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -143,7 +143,7 @@ static int oxygen_open(struct snd_pcm_substream *substream, runtime->hw.rate_min = 44100; break; case PCM_MULTICH: - runtime->hw.channels_max = chip->model.dac_channels; + runtime->hw.channels_max = chip->model.dac_channels_pcm; break; } if (chip->model.pcm_hardware_filter) diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index de32895b3172..a25197ca39a1 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -426,7 +426,8 @@ static const struct oxygen_model model_xonar_d1 = { PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | AC97_FMIC_SWITCH, - .dac_channels = 8, + .dac_channels_pcm = 8, + .dac_channels_mixer = 8, .dac_volume_min = 127 - 60, .dac_volume_max = 127, .function_flags = OXYGEN_FUNCTION_2WIRE, diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index bf357c01afd2..b55149e9be81 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -1094,7 +1094,8 @@ static const struct oxygen_model model_xonar_d2 = { MIDI_OUTPUT | MIDI_INPUT | AC97_CD_INPUT, - .dac_channels = 8, + .dac_channels_pcm = 8, + .dac_channels_mixer = 8, .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, .misc_flags = OXYGEN_MISC_MIDI, @@ -1127,7 +1128,8 @@ static const struct oxygen_model model_xonar_hdav = { PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF, - .dac_channels = 8, + .dac_channels_pcm = 8, + .dac_channels_mixer = 2, .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, .misc_flags = OXYGEN_MISC_MIDI, @@ -1157,7 +1159,8 @@ static const struct oxygen_model model_xonar_st = { PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | AC97_FMIC_SWITCH, - .dac_channels = 2, + .dac_channels_pcm = 2, + .dac_channels_mixer = 2, .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, .function_flags = OXYGEN_FUNCTION_2WIRE, @@ -1187,6 +1190,7 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, break; case GPIO_DB_H6: chip->model.shortname = "Xonar HDAV1.3+H6"; + chip->model.dac_channels_mixer = 8; chip->model.private_data = 1; break; } @@ -1200,7 +1204,8 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, break; case GPIO_DB_H6: chip->model.shortname = "Xonar ST+H6"; - chip->model.dac_channels = 8; + chip->model.dac_channels_pcm = 8; + chip->model.dac_channels_mixer = 8; chip->model.private_data = 1; break; } diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 1705d1e93115..da92cc24eed2 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -1135,7 +1135,8 @@ static const struct oxygen_model model_xonar_ds = { .device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_1, - .dac_channels = 8, + .dac_channels_pcm = 8, + .dac_channels_mixer = 8, .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, .function_flags = OXYGEN_FUNCTION_SPI, -- cgit v1.2.3 From 5b8bf2a54fb13e40519ee846ce27bc8a2d7a7878 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 16:14:52 +0100 Subject: ALSA: oxygen: simplify model-specific MCLK handling Replace the get_i2s_mclk callback with tables of MCLK values. This simplifies the MCLK-handling code in both the framework and the model- specific drivers. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 3 +- sound/pci/oxygen/oxygen.h | 10 +++-- sound/pci/oxygen/oxygen_lib.c | 36 ++++++++++++------ sound/pci/oxygen/oxygen_pcm.c | 39 +++++++++++-------- sound/pci/oxygen/oxygen_regs.h | 8 ++-- sound/pci/oxygen/xonar_cs43xx.c | 3 +- sound/pci/oxygen/xonar_pcm179x.c | 82 ++++++++++++---------------------------- sound/pci/oxygen/xonar_wm87x6.c | 3 +- 8 files changed, 89 insertions(+), 95 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index fe7ed4fc9f46..784d500c700f 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -568,7 +568,6 @@ static const struct oxygen_model model_generic = { .mixer_init = generic_wm8785_mixer_init, .cleanup = generic_cleanup, .resume = generic_resume, - .get_i2s_mclk = oxygen_default_i2s_mclk, .set_dac_params = set_ak4396_params, .set_adc_params = set_wm8785_params, .update_dac_volume = update_ak4396_volume, @@ -589,6 +588,8 @@ static const struct oxygen_model model_generic = { .dac_volume_max = 255, .function_flags = OXYGEN_FUNCTION_SPI | OXYGEN_FUNCTION_ENABLE_SPI_4_5, + .dac_mclks = OXYGEN_MCLKS(256, 256, 128), + .adc_mclks = OXYGEN_MCLKS(256, 256, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 70eff3747158..2c5fb9edcb11 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -16,6 +16,10 @@ #define PCM_AC97 5 #define PCM_COUNT 6 +#define OXYGEN_MCLKS(f_single, f_double, f_quad) ((MCLK_##f_single << 0) | \ + (MCLK_##f_double << 2) | \ + (MCLK_##f_quad << 4)) + #define OXYGEN_IO_SIZE 0x100 #define OXYGEN_EEPROM_ID 0x434d /* "CM" */ @@ -81,8 +85,6 @@ struct oxygen_model { void (*resume)(struct oxygen *chip); void (*pcm_hardware_filter)(unsigned int channel, struct snd_pcm_hardware *hardware); - unsigned int (*get_i2s_mclk)(struct oxygen *chip, unsigned int channel, - struct snd_pcm_hw_params *hw_params); void (*set_dac_params)(struct oxygen *chip, struct snd_pcm_hw_params *params); void (*set_adc_params)(struct oxygen *chip, @@ -105,6 +107,8 @@ struct oxygen_model { u8 dac_volume_max; u8 misc_flags; u8 function_flags; + u8 dac_mclks; + u8 adc_mclks; u16 dac_i2s_format; u16 adc_i2s_format; }; @@ -171,8 +175,6 @@ void oxygen_update_spdif_source(struct oxygen *chip); /* oxygen_pcm.c */ int oxygen_pcm_init(struct oxygen *chip); -unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, unsigned int channel, - struct snd_pcm_hw_params *hw_params); /* oxygen_io.c */ diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index c44c91e6fb18..77e1f0805633 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -414,28 +414,40 @@ static void oxygen_init(struct oxygen *chip) (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT)); oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2); oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT, - OXYGEN_RATE_48000 | chip->model.dac_i2s_format | - OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 | - OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); + OXYGEN_RATE_48000 | + chip->model.dac_i2s_format | + OXYGEN_I2S_MCLK(chip->model.dac_mclks) | + OXYGEN_I2S_BITS_16 | + OXYGEN_I2S_MASTER | + OXYGEN_I2S_BCLK_64); if (chip->model.device_config & CAPTURE_0_FROM_I2S_1) oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, - OXYGEN_RATE_48000 | chip->model.adc_i2s_format | - OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 | - OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); + OXYGEN_RATE_48000 | + chip->model.adc_i2s_format | + OXYGEN_I2S_MCLK(chip->model.adc_mclks) | + OXYGEN_I2S_BITS_16 | + OXYGEN_I2S_MASTER | + OXYGEN_I2S_BCLK_64); else oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, - OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); + OXYGEN_I2S_MASTER | + OXYGEN_I2S_MUTE_MCLK); if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 | CAPTURE_2_FROM_I2S_2)) oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, - OXYGEN_RATE_48000 | chip->model.adc_i2s_format | - OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 | - OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); + OXYGEN_RATE_48000 | + chip->model.adc_i2s_format | + OXYGEN_I2S_MCLK(chip->model.adc_mclks) | + OXYGEN_I2S_BITS_16 | + OXYGEN_I2S_MASTER | + OXYGEN_I2S_BCLK_64); else oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, - OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); + OXYGEN_I2S_MASTER | + OXYGEN_I2S_MUTE_MCLK); oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, - OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); + OXYGEN_I2S_MASTER | + OXYGEN_I2S_MUTE_MCLK); oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, OXYGEN_SPDIF_OUT_ENABLE | OXYGEN_SPDIF_LOOPBACK); diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index dc3c68f76df4..d5533e34ece9 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -274,17 +274,6 @@ static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params) } } -unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, - unsigned int channel, - struct snd_pcm_hw_params *hw_params) -{ - if (params_rate(hw_params) <= 96000) - return OXYGEN_I2S_MCLK_256; - else - return OXYGEN_I2S_MCLK_128; -} -EXPORT_SYMBOL(oxygen_default_i2s_mclk); - static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params) { if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) @@ -344,6 +333,26 @@ static int oxygen_hw_params(struct snd_pcm_substream *substream, return 0; } +static u16 get_mclk(struct oxygen *chip, unsigned int channel, + struct snd_pcm_hw_params *params) +{ + unsigned int mclks, shift; + + if (channel == PCM_MULTICH) + mclks = chip->model.dac_mclks; + else + mclks = chip->model.adc_mclks; + + if (params_rate(params) <= 48000) + shift = 0; + else if (params_rate(params) <= 96000) + shift = 2; + else + shift = 4; + + return OXYGEN_I2S_MCLK(mclks >> shift); +} + static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { @@ -360,8 +369,8 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, OXYGEN_REC_FORMAT_A_MASK); oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, oxygen_rate(hw_params) | - chip->model.get_i2s_mclk(chip, PCM_A, hw_params) | chip->model.adc_i2s_format | + get_mclk(chip, PCM_A, hw_params) | oxygen_i2s_bits(hw_params), OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_FORMAT_MASK | @@ -396,9 +405,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream, if (!is_ac97) oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, oxygen_rate(hw_params) | - chip->model.get_i2s_mclk(chip, PCM_B, - hw_params) | chip->model.adc_i2s_format | + get_mclk(chip, PCM_B, hw_params) | oxygen_i2s_bits(hw_params), OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_FORMAT_MASK | @@ -479,8 +487,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, oxygen_rate(hw_params) | chip->model.dac_i2s_format | - chip->model.get_i2s_mclk(chip, PCM_MULTICH, - hw_params) | + get_mclk(chip, PCM_MULTICH, hw_params) | oxygen_i2s_bits(hw_params), OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_FORMAT_MASK | diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h index 331d3d96fa21..63dc7a0ab555 100644 --- a/sound/pci/oxygen/oxygen_regs.h +++ b/sound/pci/oxygen/oxygen_regs.h @@ -139,9 +139,11 @@ #define OXYGEN_I2S_FORMAT_I2S 0x0000 #define OXYGEN_I2S_FORMAT_LJUST 0x0008 #define OXYGEN_I2S_MCLK_MASK 0x0030 /* MCLK/LRCK */ -#define OXYGEN_I2S_MCLK_128 0x0000 -#define OXYGEN_I2S_MCLK_256 0x0010 -#define OXYGEN_I2S_MCLK_512 0x0020 +#define OXYGEN_I2S_MCLK_SHIFT 4 +#define MCLK_128 0 +#define MCLK_256 1 +#define MCLK_512 2 +#define OXYGEN_I2S_MCLK(f) (((f) & 3) << OXYGEN_I2S_MCLK_SHIFT) #define OXYGEN_I2S_BITS_MASK 0x00c0 #define OXYGEN_I2S_BITS_16 0x0000 #define OXYGEN_I2S_BITS_20 0x0040 diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index a25197ca39a1..b651938f3248 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -412,7 +412,6 @@ static const struct oxygen_model model_xonar_d1 = { .cleanup = xonar_d1_cleanup, .suspend = xonar_d1_suspend, .resume = xonar_d1_resume, - .get_i2s_mclk = oxygen_default_i2s_mclk, .set_dac_params = set_cs43xx_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_cs43xx_volume, @@ -431,6 +430,8 @@ static const struct oxygen_model model_xonar_d1 = { .dac_volume_min = 127 - 60, .dac_volume_max = 127, .function_flags = OXYGEN_FUNCTION_2WIRE, + .dac_mclks = OXYGEN_MCLKS(256, 256, 128), + .adc_mclks = OXYGEN_MCLKS(256, 256, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index e15ecee2ccf7..9787193f6ed3 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -335,10 +335,6 @@ static void pcm1796_init(struct oxygen *chip) data->h6 ? PCM1796_OS_64 : PCM1796_OS_128; pcm1796_registers_init(chip); data->current_rate = 48000; - if (!data->h6) - oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, - OXYGEN_I2S_MCLK_512, - OXYGEN_I2S_MCLK_MASK); } static void xonar_d2_init(struct oxygen *chip) @@ -476,7 +472,7 @@ static void xonar_st_init(struct oxygen *chip) oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S | - (data->h6 ? OXYGEN_I2S_MCLK_256 : OXYGEN_I2S_MCLK_512) | + OXYGEN_I2S_MCLK(data->h6 ? MCLK_256 : MCLK_512) | OXYGEN_I2S_BITS_16 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); @@ -560,26 +556,6 @@ static void xonar_st_resume(struct oxygen *chip) xonar_stx_resume(chip); } -static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate) -{ - struct xonar_pcm179x *data = chip->model_data; - - if (rate <= 48000) - return data->h6 ? OXYGEN_I2S_MCLK_256 : OXYGEN_I2S_MCLK_512; - else - return OXYGEN_I2S_MCLK_128; -} - -static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip, - unsigned int channel, - struct snd_pcm_hw_params *params) -{ - if (channel == PCM_MULTICH) - return mclk_from_rate(chip, params_rate(params)); - else - return oxygen_default_i2s_mclk(chip, channel, params); -} - static void update_pcm1796_oversampling(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; @@ -640,45 +616,32 @@ static void update_cs2000_rate(struct oxygen *chip, unsigned int rate) switch (rate) { case 32000: - if (data->h6) - rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; - else - rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_512; - break; - case 44100: - if (data->h6) - rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; - else - rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_512; - break; - default: /* 48000 */ - if (data->h6) - rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; - else - rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_512; - break; case 64000: - rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; + rate_mclk = OXYGEN_RATE_32000; break; + case 44100: case 88200: - rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; - break; - case 96000: - rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; - break; case 176400: - rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_512; + rate_mclk = OXYGEN_RATE_44100; break; + default: + case 48000: + case 96000: case 192000: - rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_512; + rate_mclk = OXYGEN_RATE_48000; break; } - oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, - OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); - if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_256) + + if (rate <= 96000 && (rate > 48000 || data->h6)) { + rate_mclk |= OXYGEN_I2S_MCLK(MCLK_256); reg = CS2000_REF_CLK_DIV_1; - else + } else { + rate_mclk |= OXYGEN_I2S_MCLK(MCLK_512); reg = CS2000_REF_CLK_DIV_2; + } + + oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, + OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg); msleep(3); /* PLL lock delay */ } @@ -1047,7 +1010,6 @@ static const struct oxygen_model model_xonar_d2 = { .cleanup = xonar_d2_cleanup, .suspend = xonar_d2_suspend, .resume = xonar_d2_resume, - .get_i2s_mclk = get_pcm1796_i2s_mclk, .set_dac_params = set_pcm1796_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, @@ -1069,6 +1031,8 @@ static const struct oxygen_model model_xonar_d2 = { .misc_flags = OXYGEN_MISC_MIDI, .function_flags = OXYGEN_FUNCTION_SPI | OXYGEN_FUNCTION_ENABLE_SPI_4_5, + .dac_mclks = OXYGEN_MCLKS(512, 128, 128), + .adc_mclks = OXYGEN_MCLKS(256, 256, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; @@ -1082,7 +1046,6 @@ static const struct oxygen_model model_xonar_hdav = { .suspend = xonar_hdav_suspend, .resume = xonar_hdav_resume, .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, - .get_i2s_mclk = get_pcm1796_i2s_mclk, .set_dac_params = set_hdav_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, @@ -1102,6 +1065,8 @@ static const struct oxygen_model model_xonar_hdav = { .dac_volume_max = 255, .misc_flags = OXYGEN_MISC_MIDI, .function_flags = OXYGEN_FUNCTION_2WIRE, + .dac_mclks = OXYGEN_MCLKS(512, 128, 128), + .adc_mclks = OXYGEN_MCLKS(256, 256, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; @@ -1114,7 +1079,6 @@ static const struct oxygen_model model_xonar_st = { .cleanup = xonar_st_cleanup, .suspend = xonar_st_suspend, .resume = xonar_st_resume, - .get_i2s_mclk = get_pcm1796_i2s_mclk, .set_dac_params = set_st_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, @@ -1132,6 +1096,8 @@ static const struct oxygen_model model_xonar_st = { .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, .function_flags = OXYGEN_FUNCTION_2WIRE, + .dac_mclks = OXYGEN_MCLKS(512, 128, 128), + .adc_mclks = OXYGEN_MCLKS(256, 256, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; @@ -1159,6 +1125,7 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, case GPIO_DB_H6: chip->model.shortname = "Xonar HDAV1.3+H6"; chip->model.dac_channels_mixer = 8; + chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); break; } break; @@ -1174,6 +1141,7 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, chip->model.control_filter = xonar_st_h6_control_filter; chip->model.dac_channels_pcm = 8; chip->model.dac_channels_mixer = 8; + chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); break; } break; diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index da92cc24eed2..4f9657084603 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -1122,7 +1122,6 @@ static const struct oxygen_model model_xonar_ds = { .suspend = xonar_ds_suspend, .resume = xonar_ds_resume, .pcm_hardware_filter = wm8776_adc_hardware_filter, - .get_i2s_mclk = oxygen_default_i2s_mclk, .set_dac_params = set_wm87x6_dac_params, .set_adc_params = set_wm8776_adc_params, .update_dac_volume = update_wm87x6_volume, @@ -1140,6 +1139,8 @@ static const struct oxygen_model model_xonar_ds = { .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, .function_flags = OXYGEN_FUNCTION_SPI, + .dac_mclks = OXYGEN_MCLKS(256, 256, 128), + .adc_mclks = OXYGEN_MCLKS(256, 256, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -- cgit v1.2.3 From ce2c492090aa55ff2764f473abdb3c5a76b4a7c4 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 16:16:08 +0100 Subject: ALSA: virtuoso: reduce MCLK in double rate modes For the CSxxxx and AKxxxx DAC/ADC chips, the MCLK factor in double rate modes (64-96 kHz) can be reduced to 128x without reducing sound quality. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 6 ++++-- sound/pci/oxygen/xonar_cs43xx.c | 4 ++-- sound/pci/oxygen/xonar_pcm179x.c | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 784d500c700f..2316884afd25 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -588,7 +588,7 @@ static const struct oxygen_model model_generic = { .dac_volume_max = 255, .function_flags = OXYGEN_FUNCTION_SPI | OXYGEN_FUNCTION_ENABLE_SPI_4_5, - .dac_mclks = OXYGEN_MCLKS(256, 256, 128), + .dac_mclks = OXYGEN_MCLKS(256, 128, 128), .adc_mclks = OXYGEN_MCLKS(256, 256, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, @@ -643,8 +643,10 @@ static int __devinit get_oxygen_model(struct oxygen *chip, 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) + if (id->driver_data == MODEL_FANTASIA) { chip->model.device_config |= CAPTURE_0_FROM_I2S_1; + chip->model.adc_mclks = OXYGEN_MCLKS(256, 128, 128); + } chip->model.dac_channels_pcm = 2; chip->model.dac_channels_mixer = 2; break; diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index b651938f3248..55c52c7e19b2 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -430,8 +430,8 @@ static const struct oxygen_model model_xonar_d1 = { .dac_volume_min = 127 - 60, .dac_volume_max = 127, .function_flags = OXYGEN_FUNCTION_2WIRE, - .dac_mclks = OXYGEN_MCLKS(256, 256, 128), - .adc_mclks = OXYGEN_MCLKS(256, 256, 128), + .dac_mclks = OXYGEN_MCLKS(256, 128, 128), + .adc_mclks = OXYGEN_MCLKS(256, 128, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 9787193f6ed3..003c4800400b 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -1032,7 +1032,7 @@ static const struct oxygen_model model_xonar_d2 = { .function_flags = OXYGEN_FUNCTION_SPI | OXYGEN_FUNCTION_ENABLE_SPI_4_5, .dac_mclks = OXYGEN_MCLKS(512, 128, 128), - .adc_mclks = OXYGEN_MCLKS(256, 256, 128), + .adc_mclks = OXYGEN_MCLKS(256, 128, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; @@ -1066,7 +1066,7 @@ static const struct oxygen_model model_xonar_hdav = { .misc_flags = OXYGEN_MISC_MIDI, .function_flags = OXYGEN_FUNCTION_2WIRE, .dac_mclks = OXYGEN_MCLKS(512, 128, 128), - .adc_mclks = OXYGEN_MCLKS(256, 256, 128), + .adc_mclks = OXYGEN_MCLKS(256, 128, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; @@ -1097,7 +1097,7 @@ static const struct oxygen_model model_xonar_st = { .dac_volume_max = 255, .function_flags = OXYGEN_FUNCTION_2WIRE, .dac_mclks = OXYGEN_MCLKS(512, 128, 128), - .adc_mclks = OXYGEN_MCLKS(256, 256, 128), + .adc_mclks = OXYGEN_MCLKS(256, 128, 128), .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -- cgit v1.2.3 From 8c50b75979a198194a38d38d855f9d7e9cac2889 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 16:16:32 +0100 Subject: ALSA: oxygen: add more PCI IDs Add PCI IDs for some unknown models. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 2316884afd25..e187c951b6a0 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -84,6 +84,7 @@ enum { 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, 0x0217), .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 }, @@ -91,6 +92,8 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .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 }, + /* PCI 2.0 HD Audio */ + { OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT }, /* Kuroutoshikou CMI8787-HG2PCI */ { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_2CH_OUTPUT }, /* TempoTec HiFier Fantasia */ -- cgit v1.2.3 From 8443d2eb81e30dcc027e531eaa442cdb2477c5ab Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 16:17:26 +0100 Subject: ALSA: oxygen: add X-Meridian 2G support Add support for the AuzenTech X-Meridian 7.1 2G sound card. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/Kconfig | 1 + sound/pci/oxygen/oxygen.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 7124340038ea..5cd5c9623127 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1527,6 +1527,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for sound cards based on the C-Media CMI8787/8788 chip: * Asound A-8788 * AuzenTech X-Meridian + * AuzenTech X-Meridian 2G * Bgears b-Enspirer * Club3D Theatron DTS * HT-Omega Claro (plus) diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7b2678a25ca0..ddb5e6969bb4 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -218,6 +218,7 @@ config SND_OXYGEN C-Media CMI8788 (Oxygen HD Audio) chip: * Asound A-8788 * AuzenTech X-Meridian + * AuzenTech X-Meridian 2G * Bgears b-Enspirer * Club3D Theatron DTS * HT-Omega Claro (plus) diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index e187c951b6a0..304f1a5681f3 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -102,6 +102,8 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_2CH_OUTPUT }, /* AuzenTech X-Meridian */ { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, + /* AuzenTech X-Meridian 2G */ + { OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN }, /* HT-Omega Claro */ { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, /* HT-Omega Claro halo */ -- cgit v1.2.3 From 66410bfdf14f7c2ad3b2d4a8adeab41d368b6f05 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 16:20:29 +0100 Subject: ALSA: oxygen: add Xonar DG support Add experimental support for the Asus Xonar DG sound card. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 3 +- sound/pci/Kconfig | 3 +- sound/pci/oxygen/Makefile | 2 +- sound/pci/oxygen/cs4245.h | 107 +++++ sound/pci/oxygen/oxygen.c | 11 +- sound/pci/oxygen/oxygen_mixer.c | 14 +- sound/pci/oxygen/xonar_dg.c | 593 ++++++++++++++++++++++++ sound/pci/oxygen/xonar_dg.h | 8 + 8 files changed, 735 insertions(+), 6 deletions(-) create mode 100644 sound/pci/oxygen/cs4245.h create mode 100644 sound/pci/oxygen/xonar_dg.c create mode 100644 sound/pci/oxygen/xonar_dg.h (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 5cd5c9623127..805ce9124c3f 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1524,8 +1524,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module snd-oxygen ----------------- - Module for sound cards based on the C-Media CMI8787/8788 chip: + Module for sound cards based on the C-Media CMI8786/8787/8788 chip: * Asound A-8788 + * Asus Xonar DG * AuzenTech X-Meridian * AuzenTech X-Meridian 2G * Bgears b-Enspirer diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index ddb5e6969bb4..f0bcf689de24 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -209,7 +209,7 @@ config SND_OXYGEN_LIB tristate config SND_OXYGEN - tristate "C-Media 8787, 8788 (Oxygen)" + tristate "C-Media 8786, 8787, 8788 (Oxygen)" select SND_OXYGEN_LIB select SND_PCM select SND_MPU401_UART @@ -217,6 +217,7 @@ config SND_OXYGEN Say Y here to include support for sound cards based on the C-Media CMI8788 (Oxygen HD Audio) chip: * Asound A-8788 + * Asus Xonar DG * AuzenTech X-Meridian * AuzenTech X-Meridian 2G * Bgears b-Enspirer diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index bd67c0d7779c..0f8726551fde 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile @@ -1,5 +1,5 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o -snd-oxygen-objs := oxygen.o +snd-oxygen-objs := oxygen.o xonar_dg.o snd-virtuoso-objs := virtuoso.o xonar_lib.o \ xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o diff --git a/sound/pci/oxygen/cs4245.h b/sound/pci/oxygen/cs4245.h new file mode 100644 index 000000000000..5e0197e07dd1 --- /dev/null +++ b/sound/pci/oxygen/cs4245.h @@ -0,0 +1,107 @@ +#define CS4245_CHIP_ID 0x01 +#define CS4245_POWER_CTRL 0x02 +#define CS4245_DAC_CTRL_1 0x03 +#define CS4245_ADC_CTRL 0x04 +#define CS4245_MCLK_FREQ 0x05 +#define CS4245_SIGNAL_SEL 0x06 +#define CS4245_PGA_B_CTRL 0x07 +#define CS4245_PGA_A_CTRL 0x08 +#define CS4245_ANALOG_IN 0x09 +#define CS4245_DAC_A_CTRL 0x0a +#define CS4245_DAC_B_CTRL 0x0b +#define CS4245_DAC_CTRL_2 0x0c +#define CS4245_INT_STATUS 0x0d +#define CS4245_INT_MASK 0x0e +#define CS4245_INT_MODE_MSB 0x0f +#define CS4245_INT_MODE_LSB 0x10 + +/* Chip ID */ +#define CS4245_CHIP_PART_MASK 0xf0 +#define CS4245_CHIP_REV_MASK 0x0f + +/* Power Control */ +#define CS4245_FREEZE 0x80 +#define CS4245_PDN_MIC 0x08 +#define CS4245_PDN_ADC 0x04 +#define CS4245_PDN_DAC 0x02 +#define CS4245_PDN 0x01 + +/* DAC Control */ +#define CS4245_DAC_FM_MASK 0xc0 +#define CS4245_DAC_FM_SINGLE 0x00 +#define CS4245_DAC_FM_DOUBLE 0x40 +#define CS4245_DAC_FM_QUAD 0x80 +#define CS4245_DAC_DIF_MASK 0x30 +#define CS4245_DAC_DIF_LJUST 0x00 +#define CS4245_DAC_DIF_I2S 0x10 +#define CS4245_DAC_DIF_RJUST_16 0x20 +#define CS4245_DAC_DIF_RJUST_24 0x30 +#define CS4245_RESERVED_1 0x08 +#define CS4245_MUTE_DAC 0x04 +#define CS4245_DEEMPH 0x02 +#define CS4245_DAC_MASTER 0x01 + +/* ADC Control */ +#define CS4245_ADC_FM_MASK 0xc0 +#define CS4245_ADC_FM_SINGLE 0x00 +#define CS4245_ADC_FM_DOUBLE 0x40 +#define CS4245_ADC_FM_QUAD 0x80 +#define CS4245_ADC_DIF_MASK 0x10 +#define CS4245_ADC_DIF_LJUST 0x00 +#define CS4245_ADC_DIF_I2S 0x10 +#define CS4245_MUTE_ADC 0x04 +#define CS4245_HPF_FREEZE 0x02 +#define CS4245_ADC_MASTER 0x01 + +/* MCLK Frequency */ +#define CS4245_MCLK1_MASK 0x70 +#define CS4245_MCLK1_SHIFT 4 +#define CS4245_MCLK2_MASK 0x07 +#define CS4245_MCLK2_SHIFT 0 +#define CS4245_MCLK_1 0 +#define CS4245_MCLK_1_5 1 +#define CS4245_MCLK_2 2 +#define CS4245_MCLK_3 3 +#define CS4245_MCLK_4 4 + +/* Signal Selection */ +#define CS4245_A_OUT_SEL_MASK 0x60 +#define CS4245_A_OUT_SEL_HIZ 0x00 +#define CS4245_A_OUT_SEL_DAC 0x20 +#define CS4245_A_OUT_SEL_PGA 0x40 +#define CS4245_LOOP 0x02 +#define CS4245_ASYNCH 0x01 + +/* Channel B/A PGA Control */ +#define CS4245_PGA_GAIN_MASK 0x3f + +/* ADC Input Control */ +#define CS4245_PGA_SOFT 0x10 +#define CS4245_PGA_ZERO 0x08 +#define CS4245_SEL_MASK 0x07 +#define CS4245_SEL_MIC 0x00 +#define CS4245_SEL_INPUT_1 0x01 +#define CS4245_SEL_INPUT_2 0x02 +#define CS4245_SEL_INPUT_3 0x03 +#define CS4245_SEL_INPUT_4 0x04 +#define CS4245_SEL_INPUT_5 0x05 +#define CS4245_SEL_INPUT_6 0x06 + +/* DAC Channel A/B Volume Control */ +#define CS4245_VOL_MASK 0xff + +/* DAC Control 2 */ +#define CS4245_DAC_SOFT 0x80 +#define CS4245_DAC_ZERO 0x40 +#define CS4245_INVERT_DAC 0x20 +#define CS4245_INT_ACTIVE_HIGH 0x01 + +/* Interrupt Status/Mask/Mode */ +#define CS4245_ADC_CLK_ERR 0x08 +#define CS4245_DAC_CLK_ERR 0x04 +#define CS4245_ADC_OVFL 0x02 +#define CS4245_ADC_UNDRFL 0x01 + + +#define CS4245_SPI_ADDRESS (0x9e << 16) +#define CS4245_SPI_WRITE (0 << 16) diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 304f1a5681f3..b59aeefd14db 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -53,13 +53,16 @@ #include #include #include "oxygen.h" +#include "xonar_dg.h" #include "ak4396.h" #include "wm8785.h" MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("C-Media CMI8788 driver"); MODULE_LICENSE("GPL v2"); -MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); +MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8786}" + ",{C-Media,CMI8787}" + ",{C-Media,CMI8788}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; @@ -79,6 +82,7 @@ enum { MODEL_CLARO_HALO, MODEL_FANTASIA, MODEL_2CH_OUTPUT, + MODEL_XONAR_DG, }; static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { @@ -92,6 +96,8 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .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 }, + /* Asus Xonar DG */ + { OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG }, /* PCI 2.0 HD Audio */ { OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT }, /* Kuroutoshikou CMI8787-HG2PCI */ @@ -655,6 +661,9 @@ static int __devinit get_oxygen_model(struct oxygen *chip, chip->model.dac_channels_pcm = 2; chip->model.dac_channels_mixer = 2; break; + case MODEL_XONAR_DG: + chip->model = model_xonar_dg; + break; } if (id->driver_data == MODEL_MERIDIAN || id->driver_data == MODEL_CLARO_HALO) { diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 242c1cac69b8..d327c36fbddf 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -97,6 +97,16 @@ static int dac_mute_put(struct snd_kcontrol *ctl, return changed; } +static unsigned int upmix_item_count(struct oxygen *chip) +{ + if (chip->model.dac_channels_pcm < 8) + return 2; + else if (chip->model.update_center_lfe_mix) + return 5; + else + return 3; +} + static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { static const char *const names[5] = { @@ -107,7 +117,7 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) "Front+Surround+Center/LFE+Back", }; struct oxygen *chip = ctl->private_data; - unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; + unsigned int count = upmix_item_count(chip); info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; info->count = 1; @@ -188,7 +198,7 @@ void oxygen_update_dac_routing(struct oxygen *chip) static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; - unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; + unsigned int count = upmix_item_count(chip); int changed; if (value->value.enumerated.item[0] >= count) diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c new file mode 100644 index 000000000000..7ed3284d7d5b --- /dev/null +++ b/sound/pci/oxygen/xonar_dg.c @@ -0,0 +1,593 @@ +/* + * card driver for the Xonar DG + * + * Copyright (c) Clemens Ladisch + * + * + * 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, see . + */ + +/* + * Xonar DG + * -------- + * + * CMI8788: + * + * SPI 0 -> CS4245 + * + * GPIO 3 <- ? + * GPIO 4 <- headphone detect + * GPIO 5 -> route input jack to line-in (0) or mic-in (1) + * GPIO 6 -> route input jack to line-in (0) or mic-in (1) + * GPIO 7 -> enable rear headphone amp + * GPIO 8 -> enable output to speakers + * + * CS4245: + * + * input 1 <- aux + * input 2 <- front mic + * input 4 <- line/mic + * aux out -> front panel headphones + */ + +#include +#include +#include +#include +#include +#include +#include "oxygen.h" +#include "xonar_dg.h" +#include "cs4245.h" + +#define GPIO_MAGIC 0x0008 +#define GPIO_HP_DETECT 0x0010 +#define GPIO_INPUT_ROUTE 0x0060 +#define GPIO_HP_REAR 0x0080 +#define GPIO_OUTPUT_ENABLE 0x0100 + +struct dg { + unsigned int output_sel; + s8 input_vol[4][2]; + unsigned int input_sel; + u8 hp_vol_att; + u8 cs4245_regs[0x11]; +}; + +static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) +{ + struct dg *data = chip->model_data; + + oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | + OXYGEN_SPI_DATA_LENGTH_3 | + OXYGEN_SPI_CLOCK_1280 | + (0 << OXYGEN_SPI_CODEC_SHIFT) | + OXYGEN_SPI_CEN_LATCH_CLOCK_HI, + CS4245_SPI_ADDRESS | + CS4245_SPI_WRITE | + (value << 8) | reg); + data->cs4245_regs[reg] = value; +} + +static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) +{ + struct dg *data = chip->model_data; + + if (value != data->cs4245_regs[reg]) + cs4245_write(chip, reg, value); +} + +static void cs4245_registers_init(struct oxygen *chip) +{ + struct dg *data = chip->model_data; + + cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN); + cs4245_write(chip, CS4245_DAC_CTRL_1, + data->cs4245_regs[CS4245_DAC_CTRL_1]); + cs4245_write(chip, CS4245_ADC_CTRL, + data->cs4245_regs[CS4245_ADC_CTRL]); + cs4245_write(chip, CS4245_SIGNAL_SEL, + data->cs4245_regs[CS4245_SIGNAL_SEL]); + cs4245_write(chip, CS4245_PGA_B_CTRL, + data->cs4245_regs[CS4245_PGA_B_CTRL]); + cs4245_write(chip, CS4245_PGA_A_CTRL, + data->cs4245_regs[CS4245_PGA_A_CTRL]); + cs4245_write(chip, CS4245_ANALOG_IN, + data->cs4245_regs[CS4245_ANALOG_IN]); + cs4245_write(chip, CS4245_DAC_A_CTRL, + data->cs4245_regs[CS4245_DAC_A_CTRL]); + cs4245_write(chip, CS4245_DAC_B_CTRL, + data->cs4245_regs[CS4245_DAC_B_CTRL]); + cs4245_write(chip, CS4245_DAC_CTRL_2, + CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC); + cs4245_write(chip, CS4245_INT_MASK, 0); + cs4245_write(chip, CS4245_POWER_CTRL, 0); +} + +static void cs4245_init(struct oxygen *chip) +{ + struct dg *data = chip->model_data; + + data->cs4245_regs[CS4245_DAC_CTRL_1] = + CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST; + data->cs4245_regs[CS4245_ADC_CTRL] = + CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST; + data->cs4245_regs[CS4245_SIGNAL_SEL] = + CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH; + data->cs4245_regs[CS4245_PGA_B_CTRL] = 0; + data->cs4245_regs[CS4245_PGA_A_CTRL] = 0; + data->cs4245_regs[CS4245_ANALOG_IN] = + CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4; + data->cs4245_regs[CS4245_DAC_A_CTRL] = 0; + data->cs4245_regs[CS4245_DAC_B_CTRL] = 0; + cs4245_registers_init(chip); + snd_component_add(chip->card, "CS4245"); +} + +static void dg_output_enable(struct oxygen *chip) +{ + msleep(2500); + oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); +} + +static void dg_init(struct oxygen *chip) +{ + struct dg *data = chip->model_data; + + data->output_sel = 0; + data->input_sel = 3; + data->hp_vol_att = 2 * 16; + + cs4245_init(chip); + + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_MAGIC | GPIO_HP_DETECT); + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE); + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, + GPIO_INPUT_ROUTE | GPIO_HP_REAR); + dg_output_enable(chip); +} + +static void dg_cleanup(struct oxygen *chip) +{ + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); +} + +static void dg_suspend(struct oxygen *chip) +{ + dg_cleanup(chip); +} + +static void dg_resume(struct oxygen *chip) +{ + cs4245_registers_init(chip); + dg_output_enable(chip); +} + +static void set_cs4245_dac_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + struct dg *data = chip->model_data; + u8 value; + + value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK; + if (params_rate(params) <= 50000) + value |= CS4245_DAC_FM_SINGLE; + else if (params_rate(params) <= 100000) + value |= CS4245_DAC_FM_DOUBLE; + else + value |= CS4245_DAC_FM_QUAD; + cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value); +} + +static void set_cs4245_adc_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + struct dg *data = chip->model_data; + u8 value; + + value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK; + if (params_rate(params) <= 50000) + value |= CS4245_ADC_FM_SINGLE; + else if (params_rate(params) <= 100000) + value |= CS4245_ADC_FM_DOUBLE; + else + value |= CS4245_ADC_FM_QUAD; + cs4245_write_cached(chip, CS4245_ADC_CTRL, value); +} + +static int output_switch_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[3] = { + "Speakers", "Headphones", "FP Headphones" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 3; + if (info->value.enumerated.item >= 3) + info->value.enumerated.item = 2; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int output_switch_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + + mutex_lock(&chip->mutex); + value->value.enumerated.item[0] = data->output_sel; + mutex_unlock(&chip->mutex); + return 0; +} + +static int output_switch_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; + + 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_regs[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); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int hp_volume_offset_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[3] = { + "< 64 ohms", "64-150 ohms", "150-300 ohms" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 3; + if (info->value.enumerated.item >= 3) + info->value.enumerated.item = 2; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int hp_volume_offset_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + + mutex_lock(&chip->mutex); + if (data->hp_vol_att > 2 * 7) + value->value.enumerated.item[0] = 0; + else if (data->hp_vol_att > 0) + value->value.enumerated.item[0] = 1; + else + value->value.enumerated.item[0] = 2; + mutex_unlock(&chip->mutex); + return 0; +} + +static int hp_volume_offset_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + static const s8 atts[3] = { 2 * 16, 2 * 7, 0 }; + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + s8 att; + int changed; + + if (value->value.enumerated.item[0] > 2) + return -EINVAL; + att = atts[value->value.enumerated.item[0]]; + mutex_lock(&chip->mutex); + changed = att != data->hp_vol_att; + if (changed) { + data->hp_vol_att = att; + if (data->output_sel) { + cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att); + cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att); + } + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int input_vol_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 2 * -12; + info->value.integer.max = 2 * 12; + return 0; +} + +static int input_vol_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + unsigned int idx = ctl->private_value; + + mutex_lock(&chip->mutex); + value->value.integer.value[0] = data->input_vol[idx][0]; + value->value.integer.value[1] = data->input_vol[idx][1]; + mutex_unlock(&chip->mutex); + return 0; +} + +static int input_vol_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + unsigned int idx = ctl->private_value; + int changed = 0; + + if (value->value.integer.value[0] < 2 * -12 || + value->value.integer.value[0] > 2 * 12 || + value->value.integer.value[1] < 2 * -12 || + value->value.integer.value[1] > 2 * 12) + return -EINVAL; + mutex_lock(&chip->mutex); + changed = data->input_vol[idx][0] != value->value.integer.value[0] || + data->input_vol[idx][1] != value->value.integer.value[1]; + if (changed) { + data->input_vol[idx][0] = value->value.integer.value[0]; + data->input_vol[idx][1] = value->value.integer.value[1]; + if (idx == data->input_sel) { + cs4245_write_cached(chip, CS4245_PGA_A_CTRL, + data->input_vol[idx][0]); + cs4245_write_cached(chip, CS4245_PGA_B_CTRL, + data->input_vol[idx][1]); + } + } + mutex_unlock(&chip->mutex); + return changed; +} + +static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); + +static int input_sel_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[4] = { + "Mic", "Aux", "Front Mic", "Line" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 4; + info->value.enumerated.item &= 3; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int input_sel_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + + mutex_lock(&chip->mutex); + value->value.enumerated.item[0] = data->input_sel; + mutex_unlock(&chip->mutex); + return 0; +} + +static int input_sel_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + static const u8 sel_values[4] = { + CS4245_SEL_MIC, + CS4245_SEL_INPUT_1, + CS4245_SEL_INPUT_2, + CS4245_SEL_INPUT_4 + }; + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + int changed; + + if (value->value.enumerated.item[0] > 3) + return -EINVAL; + + mutex_lock(&chip->mutex); + changed = value->value.enumerated.item[0] != data->input_sel; + if (changed) { + data->input_sel = value->value.enumerated.item[0]; + + cs4245_write(chip, CS4245_ANALOG_IN, + (data->cs4245_regs[CS4245_ANALOG_IN] & + ~CS4245_SEL_MASK) | + sel_values[data->input_sel]); + + cs4245_write_cached(chip, CS4245_PGA_A_CTRL, + data->input_vol[data->input_sel][0]); + cs4245_write_cached(chip, CS4245_PGA_B_CTRL, + data->input_vol[data->input_sel][1]); + + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, + data->input_sel ? 0 : GPIO_INPUT_ROUTE, + GPIO_INPUT_ROUTE); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { "Active", "Frozen" }; + + 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 hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + + value->value.enumerated.item[0] = + !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); + return 0; +} + +static int hpf_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; + + mutex_lock(&chip->mutex); + reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; + if (value->value.enumerated.item[0]) + reg |= CS4245_HPF_FREEZE; + changed = reg != data->cs4245_regs[CS4245_ADC_CTRL]; + if (changed) + cs4245_write(chip, CS4245_ADC_CTRL, reg); + mutex_unlock(&chip->mutex); + return changed; +} + +#define INPUT_VOLUME(xname, index) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = input_vol_info, \ + .get = input_vol_get, \ + .put = input_vol_put, \ + .tlv = { .p = cs4245_pga_db_scale }, \ + .private_value = index, \ +} +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, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphones Impedance Playback Enum", + .info = hp_volume_offset_info, + .get = hp_volume_offset_get, + .put = hp_volume_offset_put, + }, + INPUT_VOLUME("Mic Capture Volume", 0), + INPUT_VOLUME("Aux Capture Volume", 1), + INPUT_VOLUME("Front Mic Capture Volume", 2), + INPUT_VOLUME("Line Capture Volume", 3), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = input_sel_info, + .get = input_sel_get, + .put = input_sel_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC High-pass Filter Capture Enum", + .info = hpf_info, + .get = hpf_get, + .put = hpf_put, + }, +}; + +static int dg_control_filter(struct snd_kcontrol_new *template) +{ + if (!strncmp(template->name, "Master Playback ", 16)) + return 1; + return 0; +} + +static int dg_mixer_init(struct oxygen *chip) +{ + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&dg_controls[i], chip)); + if (err < 0) + return err; + } + return 0; +} + +static void dump_cs4245_registers(struct oxygen *chip, + struct snd_info_buffer *buffer) +{ + struct dg *data = chip->model_data; + unsigned int i; + + snd_iprintf(buffer, "\nCS4245:"); + for (i = 1; i <= 0x10; ++i) + snd_iprintf(buffer, " %02x", data->cs4245_regs[i]); + snd_iprintf(buffer, "\n"); +} + +struct oxygen_model model_xonar_dg = { + .shortname = "Xonar DG", + .longname = "C-Media Oxygen HD Audio", + .chip = "CMI8786", + .init = dg_init, + .control_filter = dg_control_filter, + .mixer_init = dg_mixer_init, + .cleanup = dg_cleanup, + .suspend = dg_suspend, + .resume = dg_resume, + .set_dac_params = set_cs4245_dac_params, + .set_adc_params = set_cs4245_adc_params, + .dump_registers = dump_cs4245_registers, + .model_data_size = sizeof(struct dg), + .device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_1, + .dac_channels_pcm = 6, + .dac_channels_mixer = 0, + .function_flags = OXYGEN_FUNCTION_SPI, + .dac_mclks = OXYGEN_MCLKS(256, 128, 128), + .adc_mclks = OXYGEN_MCLKS(256, 128, 128), + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, +}; diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h new file mode 100644 index 000000000000..5688d78609a9 --- /dev/null +++ b/sound/pci/oxygen/xonar_dg.h @@ -0,0 +1,8 @@ +#ifndef XONAR_DG_H_INCLUDED +#define XONAR_DG_H_INCLUDED + +#include "oxygen.h" + +extern struct oxygen_model model_xonar_dg; + +#endif -- cgit v1.2.3 From 9600732b6caba595f34acf2abd930098ec9a0b2b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 16:25:44 +0100 Subject: ALSA: core, oxygen, virtuoso: add an enum control info helper Introduce the helper function snd_ctl_enum_info() to fill out the elem_info fields for an enumerated control. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- include/sound/control.h | 4 +++- sound/core/control.c | 28 +++++++++++++++++++++++++++- sound/pci/oxygen/oxygen.c | 16 ++-------------- sound/pci/oxygen/oxygen_mixer.c | 15 ++------------- sound/pci/oxygen/xonar_cs43xx.c | 8 +------- sound/pci/oxygen/xonar_dg.c | 30 ++++-------------------------- sound/pci/oxygen/xonar_pcm179x.c | 24 +++--------------------- sound/pci/oxygen/xonar_wm87x6.c | 25 ++++--------------------- 8 files changed, 46 insertions(+), 104 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/include/sound/control.h b/include/sound/control.h index 112374dc0c58..7715e6f00d38 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -160,12 +160,14 @@ static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id } /* - * Frequently used control callbacks + * Frequently used control callbacks/helpers */ int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); +int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, + unsigned int items, const char *const names[]); /* * virtual master control diff --git a/sound/core/control.c b/sound/core/control.c index 45a818002d99..9ce00ed20fba 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1488,7 +1488,7 @@ int snd_ctl_create(struct snd_card *card) } /* - * Frequently used control callbacks + * Frequently used control callbacks/helpers */ int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -1513,3 +1513,29 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); + +/** + * snd_ctl_enum_info - fills the info structure for an enumerated control + * @info: the structure to be filled + * @channels: the number of the control's channels; often one + * @items: the number of control values; also the size of @names + * @names: an array containing the names of all control values + * + * Sets all required fields in @info to their appropriate values. + * If the control's accessibility is not the default (readable and writable), + * the caller has to fill @info->access. + */ +int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, + unsigned int items, const char *const names[]) +{ + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = channels; + info->value.enumerated.items = items; + if (info->value.enumerated.item >= items) + info->value.enumerated.item = items - 1; + strlcpy(info->value.enumerated.name, + names[info->value.enumerated.item], + sizeof(info->value.enumerated.name)); + return 0; +} +EXPORT_SYMBOL(snd_ctl_enum_info); diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index b59aeefd14db..45427d85045e 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -415,13 +415,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, "Sharp Roll-off", "Slow Roll-off" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int rolloff_get(struct snd_kcontrol *ctl, @@ -473,13 +467,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) "None", "High-pass Filter" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index d327c36fbddf..821df1c9d1d0 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -119,13 +119,7 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) struct oxygen *chip = ctl->private_data; unsigned int count = upmix_item_count(chip); - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = count; - if (info->value.enumerated.item >= count) - info->value.enumerated.item = count - 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, count, names); } static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) @@ -659,12 +653,7 @@ static int mic_fmic_source_info(struct snd_kcontrol *ctl, { 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; + return snd_ctl_enum_info(info, 1, 2, names); } static int mic_fmic_source_get(struct snd_kcontrol *ctl, diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 55c52c7e19b2..9f72d424969c 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -298,13 +298,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, "Fast Roll-off", "Slow Roll-off" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int rolloff_get(struct snd_kcontrol *ctl, diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c index 7ed3284d7d5b..cc610ac1fc19 100644 --- a/sound/pci/oxygen/xonar_dg.c +++ b/sound/pci/oxygen/xonar_dg.c @@ -213,13 +213,7 @@ static int output_switch_info(struct snd_kcontrol *ctl, "Speakers", "Headphones", "FP Headphones" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 3, names); } static int output_switch_get(struct snd_kcontrol *ctl, @@ -276,13 +270,7 @@ static int hp_volume_offset_info(struct snd_kcontrol *ctl, "< 64 ohms", "64-150 ohms", "150-300 ohms" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 3, names); } static int hp_volume_offset_get(struct snd_kcontrol *ctl, @@ -390,12 +378,7 @@ static int input_sel_info(struct snd_kcontrol *ctl, "Mic", "Aux", "Front Mic", "Line" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 4; - info->value.enumerated.item &= 3; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 4, names); } static int input_sel_get(struct snd_kcontrol *ctl, @@ -453,12 +436,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { static const char *const names[2] = { "Active", "Frozen" }; - 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; + return snd_ctl_enum_info(info, 1, 2, names); } static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index bf4fd4bb1359..54cad38ec30a 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -678,13 +678,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, "Sharp Roll-off", "Slow Roll-off" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int rolloff_get(struct snd_kcontrol *ctl, @@ -748,13 +742,7 @@ static int st_output_switch_info(struct snd_kcontrol *ctl, "Speakers", "Headphones", "FP Headphones" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 3, names); } static int st_output_switch_get(struct snd_kcontrol *ctl, @@ -809,13 +797,7 @@ static int st_hp_volume_offset_info(struct snd_kcontrol *ctl, "< 64 ohms", "64-300 ohms", "300-600 ohms" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item > 2) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 3, names); } static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index ad48356c54e4..42d1ab136217 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -577,11 +577,6 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, const char *const *names; max = (ctl->private_value >> 12) & 0xf; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = max + 1; - if (info->value.enumerated.item > max) - info->value.enumerated.item = max; switch ((ctl->private_value >> 24) & 0x1f) { case WM8776_ALCCTRL2: names = hld; @@ -605,8 +600,7 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, default: return -ENXIO; } - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, max + 1, names); } static int wm8776_field_volume_info(struct snd_kcontrol *ctl, @@ -863,13 +857,8 @@ static int wm8776_level_control_info(struct snd_kcontrol *ctl, static const char *const names[3] = { "None", "Peak Limiter", "Automatic Level Control" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + + return snd_ctl_enum_info(info, 1, 3, names); } static int wm8776_level_control_get(struct snd_kcontrol *ctl, @@ -955,13 +944,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) "None", "High-pass Filter" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) -- cgit v1.2.3 From 64878dfbf755446f025965b742e56e4739a33b37 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 16:35:38 +0100 Subject: ALSA: oxygen: X-Meridian: add S/PDIF source selection Add a mixer control to select between the on-board and extension board S/PDIF inputs for the X-Meridian (2G). Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 77 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 45427d85045e..22cbf3e67ac4 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -28,7 +28,13 @@ * * GPIO 0 -> DFS0 of AK5385 * GPIO 1 -> DFS1 of AK5385 - * GPIO 8 -> enable headphone amplifier on HT-Omega models + * + * X-Meridian models: + * GPIO 4 -> enable extension S/PDIF input + * GPIO 6 -> enable on-board S/PDIF input + * + * Claro models: + * GPIO 8 -> enable headphone amplifier * * CM9780: * @@ -124,6 +130,10 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); #define GPIO_AK5385_DFS_DOUBLE 0x0001 #define GPIO_AK5385_DFS_QUAD 0x0002 +#define GPIO_MERIDIAN_DIG_MASK 0x0050 +#define GPIO_MERIDIAN_DIG_EXT 0x0010 +#define GPIO_MERIDIAN_DIG_BOARD 0x0040 + #define GPIO_CLARO_HP 0x0100 struct generic_data { @@ -238,6 +248,10 @@ static void generic_init(struct oxygen *chip) static void meridian_init(struct oxygen *chip) { + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_MERIDIAN_DIG_MASK); + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, + GPIO_MERIDIAN_DIG_BOARD, GPIO_MERIDIAN_DIG_MASK); ak4396_init(chip); ak5385_init(chip); } @@ -506,6 +520,51 @@ static const struct snd_kcontrol_new hpf_control = { .put = hpf_put, }; +static int meridian_dig_source_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { "On-board", "Extension" }; + + return snd_ctl_enum_info(info, 1, 2, names); +} + +static int meridian_dig_source_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + + value->value.enumerated.item[0] = + !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & + GPIO_MERIDIAN_DIG_EXT); + return 0; +} + +static int meridian_dig_source_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 old_reg, new_reg; + int changed; + + mutex_lock(&chip->mutex); + old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA); + new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK; + if (value->value.enumerated.item[0] == 0) + new_reg |= GPIO_MERIDIAN_DIG_BOARD; + else + new_reg |= GPIO_MERIDIAN_DIG_EXT; + changed = new_reg != old_reg; + if (changed) + oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg); + mutex_unlock(&chip->mutex); + return changed; +} + +static const struct snd_kcontrol_new meridian_dig_source_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Source Capture Enum", + .info = meridian_dig_source_info, + .get = meridian_dig_source_get, + .put = meridian_dig_source_put, +}; + static int generic_mixer_init(struct oxygen *chip) { return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); @@ -524,6 +583,20 @@ static int generic_wm8785_mixer_init(struct oxygen *chip) return 0; } +static int meridian_mixer_init(struct oxygen *chip) +{ + int err; + + err = generic_mixer_init(chip); + if (err < 0) + return err; + err = snd_ctl_add(chip->card, + snd_ctl_new1(&meridian_dig_source_control, chip)); + if (err < 0) + return err; + return 0; +} + static void dump_ak4396_registers(struct oxygen *chip, struct snd_info_buffer *buffer) { @@ -600,7 +673,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip, switch (id->driver_data) { case MODEL_MERIDIAN: chip->model.init = meridian_init; - chip->model.mixer_init = generic_mixer_init; + chip->model.mixer_init = meridian_mixer_init; chip->model.resume = meridian_resume; chip->model.set_adc_params = set_ak5385_params; chip->model.dump_registers = dump_ak4396_registers; -- cgit v1.2.3 From a4b1696916abc4a0b6b11fc4cc2cd52421a0c7ac Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 16:37:19 +0100 Subject: ALSA: oxygen: add some card names Instead of the generic Oxygen, use the actual card name, if known. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 22cbf3e67ac4..be264d33f9b5 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -84,10 +84,13 @@ MODULE_PARM_DESC(enable, "enable card"); enum { MODEL_CMEDIA_REF, MODEL_MERIDIAN, + MODEL_MERIDIAN_2G, MODEL_CLARO, MODEL_CLARO_HALO, MODEL_FANTASIA, + MODEL_SERENADE, MODEL_2CH_OUTPUT, + MODEL_HG2PCI, MODEL_XONAR_DG, }; @@ -107,15 +110,15 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { /* PCI 2.0 HD Audio */ { OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT }, /* Kuroutoshikou CMI8787-HG2PCI */ - { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_2CH_OUTPUT }, + { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_HG2PCI }, /* 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 }, + { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_SERENADE }, /* AuzenTech X-Meridian */ { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, /* AuzenTech X-Meridian 2G */ - { OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN }, + { OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN_2G }, /* HT-Omega Claro */ { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, /* HT-Omega Claro halo */ @@ -669,9 +672,20 @@ static const struct oxygen_model model_generic = { static int __devinit get_oxygen_model(struct oxygen *chip, const struct pci_device_id *id) { + static const char *const names[] = { + [MODEL_MERIDIAN] = "AuzenTech X-Meridian", + [MODEL_MERIDIAN_2G] = "AuzenTech X-Meridian 2G", + [MODEL_CLARO] = "HT-Omega Claro", + [MODEL_CLARO_HALO] = "HT-Omega Claro halo", + [MODEL_FANTASIA] = "TempoTec HiFier Fantasia", + [MODEL_SERENADE] = "TempoTec HiFier Serenade", + [MODEL_HG2PCI] = "CMI8787-HG2PCI", + }; + chip->model = model_generic; switch (id->driver_data) { case MODEL_MERIDIAN: + case MODEL_MERIDIAN_2G: chip->model.init = meridian_init; chip->model.mixer_init = meridian_mixer_init; chip->model.resume = meridian_resume; @@ -702,7 +716,9 @@ static int __devinit get_oxygen_model(struct oxygen *chip, CAPTURE_1_FROM_SPDIF; break; case MODEL_FANTASIA: + case MODEL_SERENADE: case MODEL_2CH_OUTPUT: + case MODEL_HG2PCI: chip->model.shortname = "C-Media CMI8787"; chip->model.chip = "CMI8787"; if (id->driver_data == MODEL_FANTASIA) @@ -731,6 +747,8 @@ static int __devinit get_oxygen_model(struct oxygen *chip, chip->model.misc_flags = OXYGEN_MISC_MIDI; chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; } + if (id->driver_data < ARRAY_SIZE(names) && names[id->driver_data]) + chip->model.shortname = names[id->driver_data]; return 0; } -- cgit v1.2.3 From 5fc51524746430179c676297fd48aaab28e1b85f Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 11 Jan 2011 10:33:40 +0100 Subject: ALSA: oxygen: fix CD/MIDI for X-Meridian (2G) Enable the X-Meridian's CD input and the X-Meridian 2G's potential MIDI ports. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index be264d33f9b5..db39cfc3b4f3 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -695,6 +695,8 @@ static int __devinit get_oxygen_model(struct oxygen *chip, PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF; + if (id->driver_data == MODEL_MERIDIAN) + chip->model.device_config |= AC97_CD_INPUT; break; case MODEL_CLARO: chip->model.init = claro_init; @@ -743,6 +745,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip, break; } if (id->driver_data == MODEL_MERIDIAN || + id->driver_data == MODEL_MERIDIAN_2G || id->driver_data == MODEL_CLARO_HALO) { chip->model.misc_flags = OXYGEN_MISC_MIDI; chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; -- cgit v1.2.3 From d1d7093f3f639e693fa763eb51d8d9c349bfd606 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 11 Jan 2011 10:35:29 +0100 Subject: ALSA: oxygen: add S/PDIF source selection for Claro cards Add a mixer control to switch between the optical and coaxial S/PDIF inputs on the HT-Omega Claro and Claro halo cards. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 92 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 4 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index db39cfc3b4f3..d7e8ddd9a67b 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -34,6 +34,7 @@ * GPIO 6 -> enable on-board S/PDIF input * * Claro models: + * GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input * GPIO 8 -> enable headphone amplifier * * CM9780: @@ -137,6 +138,7 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); #define GPIO_MERIDIAN_DIG_EXT 0x0010 #define GPIO_MERIDIAN_DIG_BOARD 0x0040 +#define GPIO_CLARO_DIG_COAX 0x0040 #define GPIO_CLARO_HP 0x0100 struct generic_data { @@ -268,6 +270,8 @@ static void claro_enable_hp(struct oxygen *chip) static void claro_init(struct oxygen *chip) { + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX); + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX); ak4396_init(chip); wm8785_init(chip); claro_enable_hp(chip); @@ -275,6 +279,8 @@ static void claro_init(struct oxygen *chip) static void claro_halo_init(struct oxygen *chip) { + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX); + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX); ak4396_init(chip); ak5385_init(chip); claro_enable_hp(chip); @@ -523,14 +529,24 @@ static const struct snd_kcontrol_new hpf_control = { .put = hpf_put, }; -static int meridian_dig_source_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) +static int meridian_dig_source_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) { static const char *const names[2] = { "On-board", "Extension" }; return snd_ctl_enum_info(info, 1, 2, names); } -static int meridian_dig_source_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +static int claro_dig_source_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { "Optical", "Coaxial" }; + + return snd_ctl_enum_info(info, 1, 2, names); +} + +static int meridian_dig_source_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; @@ -540,7 +556,19 @@ static int meridian_dig_source_get(struct snd_kcontrol *ctl, struct snd_ctl_elem return 0; } -static int meridian_dig_source_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +static int claro_dig_source_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + + value->value.enumerated.item[0] = + !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & + GPIO_CLARO_DIG_COAX); + return 0; +} + +static int meridian_dig_source_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; u16 old_reg, new_reg; @@ -560,6 +588,25 @@ static int meridian_dig_source_put(struct snd_kcontrol *ctl, struct snd_ctl_elem return changed; } +static int claro_dig_source_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 old_reg, new_reg; + int changed; + + mutex_lock(&chip->mutex); + old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA); + new_reg = old_reg & ~GPIO_CLARO_DIG_COAX; + if (value->value.enumerated.item[0]) + new_reg |= GPIO_CLARO_DIG_COAX; + changed = new_reg != old_reg; + if (changed) + oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg); + mutex_unlock(&chip->mutex); + return changed; +} + static const struct snd_kcontrol_new meridian_dig_source_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "IEC958 Source Capture Enum", @@ -568,6 +615,14 @@ static const struct snd_kcontrol_new meridian_dig_source_control = { .put = meridian_dig_source_put, }; +static const struct snd_kcontrol_new claro_dig_source_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Source Capture Enum", + .info = claro_dig_source_info, + .get = claro_dig_source_get, + .put = claro_dig_source_put, +}; + static int generic_mixer_init(struct oxygen *chip) { return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); @@ -600,6 +655,34 @@ static int meridian_mixer_init(struct oxygen *chip) return 0; } +static int claro_mixer_init(struct oxygen *chip) +{ + int err; + + err = generic_wm8785_mixer_init(chip); + if (err < 0) + return err; + err = snd_ctl_add(chip->card, + snd_ctl_new1(&claro_dig_source_control, chip)); + if (err < 0) + return err; + return 0; +} + +static int claro_halo_mixer_init(struct oxygen *chip) +{ + int err; + + err = generic_mixer_init(chip); + if (err < 0) + return err; + err = snd_ctl_add(chip->card, + snd_ctl_new1(&claro_dig_source_control, chip)); + if (err < 0) + return err; + return 0; +} + static void dump_ak4396_registers(struct oxygen *chip, struct snd_info_buffer *buffer) { @@ -700,13 +783,14 @@ static int __devinit get_oxygen_model(struct oxygen *chip, break; case MODEL_CLARO: chip->model.init = claro_init; + chip->model.mixer_init = claro_mixer_init; chip->model.cleanup = claro_cleanup; chip->model.suspend = claro_suspend; chip->model.resume = claro_resume; break; case MODEL_CLARO_HALO: chip->model.init = claro_halo_init; - chip->model.mixer_init = generic_mixer_init; + chip->model.mixer_init = claro_halo_mixer_init; chip->model.cleanup = claro_cleanup; chip->model.suspend = claro_suspend; chip->model.resume = claro_resume; -- cgit v1.2.3