diff options
Diffstat (limited to 'sound/pci/oxygen/oxygen.c')
-rw-r--r-- | sound/pci/oxygen/oxygen.c | 114 |
1 files changed, 88 insertions, 26 deletions
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index de999c6d6dd3..72db4c39007f 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * C-Media CMI8788 driver for C-Media's reference design and for the X-Meridian | 2 | * C-Media CMI8788 driver for C-Media's reference design and similar models |
3 | * | 3 | * |
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
5 | * | 5 | * |
@@ -26,6 +26,7 @@ | |||
26 | * | 26 | * |
27 | * GPIO 0 -> DFS0 of AK5385 | 27 | * GPIO 0 -> DFS0 of AK5385 |
28 | * GPIO 1 -> DFS1 of AK5385 | 28 | * GPIO 1 -> DFS1 of AK5385 |
29 | * GPIO 8 -> enable headphone amplifier on HT-Omega models | ||
29 | */ | 30 | */ |
30 | 31 | ||
31 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
@@ -61,7 +62,8 @@ MODULE_PARM_DESC(enable, "enable card"); | |||
61 | enum { | 62 | enum { |
62 | MODEL_CMEDIA_REF, /* C-Media's reference design */ | 63 | MODEL_CMEDIA_REF, /* C-Media's reference design */ |
63 | MODEL_MERIDIAN, /* AuzenTech X-Meridian */ | 64 | MODEL_MERIDIAN, /* AuzenTech X-Meridian */ |
64 | MODEL_HALO, /* HT-Omega Claro halo */ | 65 | MODEL_CLARO, /* HT-Omega Claro */ |
66 | MODEL_CLARO_HALO, /* HT-Omega Claro halo */ | ||
65 | }; | 67 | }; |
66 | 68 | ||
67 | static struct pci_device_id oxygen_ids[] __devinitdata = { | 69 | static struct pci_device_id oxygen_ids[] __devinitdata = { |
@@ -74,8 +76,8 @@ static struct pci_device_id oxygen_ids[] __devinitdata = { | |||
74 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, | 76 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, |
75 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, | 77 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, |
76 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, | 78 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, |
77 | { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF }, | 79 | { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO }, |
78 | { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO }, | 80 | { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO }, |
79 | { } | 81 | { } |
80 | }; | 82 | }; |
81 | MODULE_DEVICE_TABLE(pci, oxygen_ids); | 83 | MODULE_DEVICE_TABLE(pci, oxygen_ids); |
@@ -86,6 +88,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); | |||
86 | #define GPIO_AK5385_DFS_DOUBLE 0x0001 | 88 | #define GPIO_AK5385_DFS_DOUBLE 0x0001 |
87 | #define GPIO_AK5385_DFS_QUAD 0x0002 | 89 | #define GPIO_AK5385_DFS_QUAD 0x0002 |
88 | 90 | ||
91 | #define GPIO_CLARO_HP 0x0100 | ||
92 | |||
89 | struct generic_data { | 93 | struct generic_data { |
90 | u8 ak4396_ctl2; | 94 | u8 ak4396_ctl2; |
91 | u16 saved_wm8785_registers[2]; | 95 | u16 saved_wm8785_registers[2]; |
@@ -196,10 +200,46 @@ static void meridian_init(struct oxygen *chip) | |||
196 | ak5385_init(chip); | 200 | ak5385_init(chip); |
197 | } | 201 | } |
198 | 202 | ||
203 | static void claro_enable_hp(struct oxygen *chip) | ||
204 | { | ||
205 | msleep(300); | ||
206 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_HP); | ||
207 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP); | ||
208 | } | ||
209 | |||
210 | static void claro_init(struct oxygen *chip) | ||
211 | { | ||
212 | ak4396_init(chip); | ||
213 | wm8785_init(chip); | ||
214 | claro_enable_hp(chip); | ||
215 | } | ||
216 | |||
217 | static void claro_halo_init(struct oxygen *chip) | ||
218 | { | ||
219 | ak4396_init(chip); | ||
220 | ak5385_init(chip); | ||
221 | claro_enable_hp(chip); | ||
222 | } | ||
223 | |||
199 | static void generic_cleanup(struct oxygen *chip) | 224 | static void generic_cleanup(struct oxygen *chip) |
200 | { | 225 | { |
201 | } | 226 | } |
202 | 227 | ||
228 | static void claro_disable_hp(struct oxygen *chip) | ||
229 | { | ||
230 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP); | ||
231 | } | ||
232 | |||
233 | static void claro_cleanup(struct oxygen *chip) | ||
234 | { | ||
235 | claro_disable_hp(chip); | ||
236 | } | ||
237 | |||
238 | static void claro_suspend(struct oxygen *chip) | ||
239 | { | ||
240 | claro_disable_hp(chip); | ||
241 | } | ||
242 | |||
203 | static void generic_resume(struct oxygen *chip) | 243 | static void generic_resume(struct oxygen *chip) |
204 | { | 244 | { |
205 | ak4396_registers_init(chip); | 245 | ak4396_registers_init(chip); |
@@ -211,6 +251,12 @@ static void meridian_resume(struct oxygen *chip) | |||
211 | ak4396_registers_init(chip); | 251 | ak4396_registers_init(chip); |
212 | } | 252 | } |
213 | 253 | ||
254 | static void claro_resume(struct oxygen *chip) | ||
255 | { | ||
256 | ak4396_registers_init(chip); | ||
257 | claro_enable_hp(chip); | ||
258 | } | ||
259 | |||
214 | static void set_ak4396_params(struct oxygen *chip, | 260 | static void set_ak4396_params(struct oxygen *chip, |
215 | struct snd_pcm_hw_params *params) | 261 | struct snd_pcm_hw_params *params) |
216 | { | 262 | { |
@@ -293,30 +339,10 @@ static void set_ak5385_params(struct oxygen *chip, | |||
293 | 339 | ||
294 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | 340 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); |
295 | 341 | ||
296 | static int generic_probe(struct oxygen *chip, unsigned long driver_data) | ||
297 | { | ||
298 | if (driver_data == MODEL_MERIDIAN) { | ||
299 | chip->model.init = meridian_init; | ||
300 | chip->model.resume = meridian_resume; | ||
301 | chip->model.set_adc_params = set_ak5385_params; | ||
302 | chip->model.device_config = PLAYBACK_0_TO_I2S | | ||
303 | PLAYBACK_1_TO_SPDIF | | ||
304 | CAPTURE_0_FROM_I2S_2 | | ||
305 | CAPTURE_1_FROM_SPDIF; | ||
306 | } | ||
307 | if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) { | ||
308 | chip->model.misc_flags = OXYGEN_MISC_MIDI; | ||
309 | chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; | ||
310 | } | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static const struct oxygen_model model_generic = { | 342 | static const struct oxygen_model model_generic = { |
315 | .shortname = "C-Media CMI8788", | 343 | .shortname = "C-Media CMI8788", |
316 | .longname = "C-Media Oxygen HD Audio", | 344 | .longname = "C-Media Oxygen HD Audio", |
317 | .chip = "CMI8788", | 345 | .chip = "CMI8788", |
318 | .owner = THIS_MODULE, | ||
319 | .probe = generic_probe, | ||
320 | .init = generic_init, | 346 | .init = generic_init, |
321 | .cleanup = generic_cleanup, | 347 | .cleanup = generic_cleanup, |
322 | .resume = generic_resume, | 348 | .resume = generic_resume, |
@@ -341,6 +367,42 @@ static const struct oxygen_model model_generic = { | |||
341 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 367 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
342 | }; | 368 | }; |
343 | 369 | ||
370 | static int __devinit get_oxygen_model(struct oxygen *chip, | ||
371 | const struct pci_device_id *id) | ||
372 | { | ||
373 | chip->model = model_generic; | ||
374 | switch (id->driver_data) { | ||
375 | case MODEL_MERIDIAN: | ||
376 | chip->model.init = meridian_init; | ||
377 | chip->model.resume = meridian_resume; | ||
378 | chip->model.set_adc_params = set_ak5385_params; | ||
379 | chip->model.device_config = PLAYBACK_0_TO_I2S | | ||
380 | PLAYBACK_1_TO_SPDIF | | ||
381 | CAPTURE_0_FROM_I2S_2 | | ||
382 | CAPTURE_1_FROM_SPDIF; | ||
383 | break; | ||
384 | case MODEL_CLARO: | ||
385 | chip->model.init = claro_init; | ||
386 | chip->model.cleanup = claro_cleanup; | ||
387 | chip->model.suspend = claro_suspend; | ||
388 | chip->model.resume = claro_resume; | ||
389 | break; | ||
390 | case MODEL_CLARO_HALO: | ||
391 | chip->model.init = claro_halo_init; | ||
392 | chip->model.cleanup = claro_cleanup; | ||
393 | chip->model.suspend = claro_suspend; | ||
394 | chip->model.resume = claro_resume; | ||
395 | chip->model.set_adc_params = set_ak5385_params; | ||
396 | break; | ||
397 | } | ||
398 | if (id->driver_data == MODEL_MERIDIAN || | ||
399 | id->driver_data == MODEL_CLARO_HALO) { | ||
400 | chip->model.misc_flags = OXYGEN_MISC_MIDI; | ||
401 | chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; | ||
402 | } | ||
403 | return 0; | ||
404 | } | ||
405 | |||
344 | static int __devinit generic_oxygen_probe(struct pci_dev *pci, | 406 | static int __devinit generic_oxygen_probe(struct pci_dev *pci, |
345 | const struct pci_device_id *pci_id) | 407 | const struct pci_device_id *pci_id) |
346 | { | 408 | { |
@@ -353,8 +415,8 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci, | |||
353 | ++dev; | 415 | ++dev; |
354 | return -ENOENT; | 416 | return -ENOENT; |
355 | } | 417 | } |
356 | err = oxygen_pci_probe(pci, index[dev], id[dev], | 418 | err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, |
357 | &model_generic, pci_id->driver_data); | 419 | oxygen_ids, get_oxygen_model); |
358 | if (err >= 0) | 420 | if (err >= 0) |
359 | ++dev; | 421 | ++dev; |
360 | return err; | 422 | return err; |