From bb71858853a5c9616eea98512f4075d4f081154d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 19 Feb 2009 08:37:13 +0100 Subject: sound: oxygen: make the owner module a parameter of the probe function Move the owner field out of the oxygen_model structure and make it a parameter of oxygen_pci_probe(), because the actual owner module does not depend on the card model. Furthermore, moving it out of the model structure allows us to create the card structure before the actual model is known. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index de999c6d6dd..12b6c2137d5 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -315,7 +315,6 @@ static const struct oxygen_model model_generic = { .shortname = "C-Media CMI8788", .longname = "C-Media Oxygen HD Audio", .chip = "CMI8788", - .owner = THIS_MODULE, .probe = generic_probe, .init = generic_init, .cleanup = generic_cleanup, @@ -353,7 +352,7 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci, ++dev; return -ENOENT; } - err = oxygen_pci_probe(pci, index[dev], id[dev], + err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, &model_generic, pci_id->driver_data); if (err >= 0) ++dev; -- cgit v1.2.3 From 30459d7b1843cbdea56ca120c8cac10dc5613e90 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 19 Feb 2009 08:42:44 +0100 Subject: sound: oxygen: handle cards with broken EEPROM Under as yet unknown circumstances, the first word of the sound card's EEPROM gets overwritten. When this has happened, we cannot rely on the subsystem IDs that the kernel reads from the PCI configuration registers. Instead, we read the IDs directly from the EEPROM and do the ID matching manually. Because the model-specific driver cannot determine the model before calling oxygen_pci_probe(), that function now gets a get_model() callback as parameter. The customizing of the model structure, which was formerly done by the probe() callback, also has moved into get_model(). Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 12b6c2137d5..f2c37f379d3 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -293,29 +293,10 @@ static void set_ak5385_params(struct oxygen *chip, static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); -static int generic_probe(struct oxygen *chip, unsigned long driver_data) -{ - if (driver_data == MODEL_MERIDIAN) { - chip->model.init = meridian_init; - chip->model.resume = meridian_resume; - chip->model.set_adc_params = set_ak5385_params; - chip->model.device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2 | - CAPTURE_1_FROM_SPDIF; - } - if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) { - chip->model.misc_flags = OXYGEN_MISC_MIDI; - chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; - } - return 0; -} - static const struct oxygen_model model_generic = { .shortname = "C-Media CMI8788", .longname = "C-Media Oxygen HD Audio", .chip = "CMI8788", - .probe = generic_probe, .init = generic_init, .cleanup = generic_cleanup, .resume = generic_resume, @@ -340,6 +321,29 @@ static const struct oxygen_model model_generic = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; +static int __devinit get_oxygen_model(struct oxygen *chip, + const struct pci_device_id *id) +{ + chip->model = model_generic; + switch (id->driver_data) { + case MODEL_MERIDIAN: + chip->model.init = meridian_init; + chip->model.resume = meridian_resume; + chip->model.set_adc_params = set_ak5385_params; + chip->model.device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_2 | + CAPTURE_1_FROM_SPDIF; + break; + } + if (id->driver_data == MODEL_MERIDIAN || + id->driver_data == MODEL_HALO) { + chip->model.misc_flags = OXYGEN_MISC_MIDI; + chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; + } + return 0; +} + static int __devinit generic_oxygen_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -353,7 +357,7 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci, return -ENOENT; } err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, - &model_generic, pci_id->driver_data); + oxygen_ids, get_oxygen_model); if (err >= 0) ++dev; return err; -- cgit v1.2.3 From d91b424d6d7bda0773b6b6b606d48d089c4f5115 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 20 Feb 2009 09:31:14 +0100 Subject: sound: oxygen: handle AK5385 ADC on Claro halo cards The HT-Omega Claro halo's ADC is an AK5385 instead of a WM8785, so we should handle the ADC parameters as we do with the X-Meridian. Using the code for the wrong ADC does not seem to have any audible effects, and the Windows driver does it, but it is nonetheless a good idea to run the AK5385 with an oversampling ratio that is not outside the documented limits. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index f2c37f379d3..1d8e2b29745 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -196,6 +196,12 @@ static void meridian_init(struct oxygen *chip) ak5385_init(chip); } +static void halo_init(struct oxygen *chip) +{ + ak4396_init(chip); + ak5385_init(chip); +} + static void generic_cleanup(struct oxygen *chip) { } @@ -211,6 +217,11 @@ static void meridian_resume(struct oxygen *chip) ak4396_registers_init(chip); } +static void halo_resume(struct oxygen *chip) +{ + ak4396_registers_init(chip); +} + static void set_ak4396_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { @@ -335,6 +346,11 @@ static int __devinit get_oxygen_model(struct oxygen *chip, CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF; break; + case MODEL_HALO: + chip->model.init = halo_init; + chip->model.resume = halo_resume; + chip->model.set_adc_params = set_ak5385_params; + break; } if (id->driver_data == MODEL_MERIDIAN || id->driver_data == MODEL_HALO) { -- cgit v1.2.3 From 873591db59e66434fd0a484c92f69fc21100b33d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 Mar 2009 09:12:55 +0100 Subject: sound: oxygen: enable headphone output on Claro cards On the HT-Omega Claro (halo) sound cards, the headphone amplifier must be enabled explicitly by setting a GPIO bit. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 63 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 10 deletions(-) (limited to 'sound/pci/oxygen/oxygen.c') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 1d8e2b29745..72db4c39007 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -1,5 +1,5 @@ /* - * C-Media CMI8788 driver for C-Media's reference design and for the X-Meridian + * C-Media CMI8788 driver for C-Media's reference design and similar models * * Copyright (c) Clemens Ladisch * @@ -26,6 +26,7 @@ * * GPIO 0 -> DFS0 of AK5385 * GPIO 1 -> DFS1 of AK5385 + * GPIO 8 -> enable headphone amplifier on HT-Omega models */ #include @@ -61,7 +62,8 @@ MODULE_PARM_DESC(enable, "enable card"); enum { MODEL_CMEDIA_REF, /* C-Media's reference design */ MODEL_MERIDIAN, /* AuzenTech X-Meridian */ - MODEL_HALO, /* HT-Omega Claro halo */ + MODEL_CLARO, /* HT-Omega Claro */ + MODEL_CLARO_HALO, /* HT-Omega Claro halo */ }; static struct pci_device_id oxygen_ids[] __devinitdata = { @@ -74,8 +76,8 @@ static struct pci_device_id oxygen_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, { 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_CMEDIA_REF }, - { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO }, + { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, + { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO }, { } }; MODULE_DEVICE_TABLE(pci, oxygen_ids); @@ -86,6 +88,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); #define GPIO_AK5385_DFS_DOUBLE 0x0001 #define GPIO_AK5385_DFS_QUAD 0x0002 +#define GPIO_CLARO_HP 0x0100 + struct generic_data { u8 ak4396_ctl2; u16 saved_wm8785_registers[2]; @@ -196,16 +200,46 @@ static void meridian_init(struct oxygen *chip) ak5385_init(chip); } -static void halo_init(struct oxygen *chip) +static void claro_enable_hp(struct oxygen *chip) +{ + msleep(300); + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_HP); + oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP); +} + +static void claro_init(struct oxygen *chip) +{ + ak4396_init(chip); + wm8785_init(chip); + claro_enable_hp(chip); +} + +static void claro_halo_init(struct oxygen *chip) { ak4396_init(chip); ak5385_init(chip); + claro_enable_hp(chip); } static void generic_cleanup(struct oxygen *chip) { } +static void claro_disable_hp(struct oxygen *chip) +{ + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP); +} + +static void claro_cleanup(struct oxygen *chip) +{ + claro_disable_hp(chip); +} + +static void claro_suspend(struct oxygen *chip) +{ + claro_disable_hp(chip); +} + static void generic_resume(struct oxygen *chip) { ak4396_registers_init(chip); @@ -217,9 +251,10 @@ static void meridian_resume(struct oxygen *chip) ak4396_registers_init(chip); } -static void halo_resume(struct oxygen *chip) +static void claro_resume(struct oxygen *chip) { ak4396_registers_init(chip); + claro_enable_hp(chip); } static void set_ak4396_params(struct oxygen *chip, @@ -346,14 +381,22 @@ static int __devinit get_oxygen_model(struct oxygen *chip, CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF; break; - case MODEL_HALO: - chip->model.init = halo_init; - chip->model.resume = halo_resume; + case MODEL_CLARO: + chip->model.init = claro_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.cleanup = claro_cleanup; + chip->model.suspend = claro_suspend; + chip->model.resume = claro_resume; chip->model.set_adc_params = set_ak5385_params; break; } if (id->driver_data == MODEL_MERIDIAN || - id->driver_data == MODEL_HALO) { + 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