diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2008-09-22 03:00:30 -0400 |
---|---|---|
committer | Clemens Ladisch <clemens@ladisch.de> | 2008-09-22 03:00:30 -0400 |
commit | fe10662c3c7e1a77cac7949a4b269622da663c2e (patch) | |
tree | c866cee6729fd5db6239a11cd8b54ad896f68eae | |
parent | 4bd0c3a690594b4037c3edc49e6475f1df13c59d (diff) |
ALSA: virtuoso: handle D2X/DX dynamically
The Xonar D2X and DX are very similar to the D2 and D1, respectively, so
we can handle the differences dynamically instead of using a separate
model structure for each one.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
-rw-r--r-- | sound/pci/oxygen/virtuoso.c | 241 |
1 files changed, 99 insertions, 142 deletions
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 4aa2857a1b05..c4ac91f80235 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -128,6 +128,7 @@ MODULE_DEVICE_TABLE(pci, xonar_ids); | |||
128 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ | 128 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ |
129 | 129 | ||
130 | struct xonar_data { | 130 | struct xonar_data { |
131 | unsigned int model; | ||
131 | unsigned int anti_pop_delay; | 132 | unsigned int anti_pop_delay; |
132 | u16 output_enable_bit; | 133 | u16 output_enable_bit; |
133 | u8 ext_power_reg; | 134 | u8 ext_power_reg; |
@@ -139,6 +140,8 @@ struct xonar_data { | |||
139 | u8 cs4362a_fm; | 140 | u8 cs4362a_fm; |
140 | }; | 141 | }; |
141 | 142 | ||
143 | static void xonar_gpio_changed(struct oxygen *chip); | ||
144 | |||
142 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, | 145 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, |
143 | u8 reg, u8 value) | 146 | u8 reg, u8 value) |
144 | { | 147 | { |
@@ -180,6 +183,7 @@ static void xonar_common_init(struct oxygen *chip) | |||
180 | oxygen_set_bits8(chip, data->ext_power_int_reg, | 183 | oxygen_set_bits8(chip, data->ext_power_int_reg, |
181 | data->ext_power_bit); | 184 | data->ext_power_bit); |
182 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | 185 | chip->interrupt_mask |= OXYGEN_INT_GPIO; |
186 | chip->model.gpio_changed = xonar_gpio_changed; | ||
183 | data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) | 187 | data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) |
184 | & data->ext_power_bit); | 188 | & data->ext_power_bit); |
185 | } | 189 | } |
@@ -234,6 +238,13 @@ static void xonar_d2_init(struct oxygen *chip) | |||
234 | data->anti_pop_delay = 300; | 238 | data->anti_pop_delay = 300; |
235 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; | 239 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; |
236 | data->pcm1796_oversampling = PCM1796_OS_64; | 240 | data->pcm1796_oversampling = PCM1796_OS_64; |
241 | if (data->model == MODEL_D2X) { | ||
242 | data->ext_power_reg = OXYGEN_GPIO_DATA; | ||
243 | data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; | ||
244 | data->ext_power_bit = GPIO_D2X_EXT_POWER; | ||
245 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
246 | GPIO_D2X_EXT_POWER); | ||
247 | } | ||
237 | 248 | ||
238 | pcm1796_init(chip); | 249 | pcm1796_init(chip); |
239 | 250 | ||
@@ -246,17 +257,6 @@ static void xonar_d2_init(struct oxygen *chip) | |||
246 | snd_component_add(chip->card, "CS5381"); | 257 | snd_component_add(chip->card, "CS5381"); |
247 | } | 258 | } |
248 | 259 | ||
249 | static void xonar_d2x_init(struct oxygen *chip) | ||
250 | { | ||
251 | struct xonar_data *data = chip->model_data; | ||
252 | |||
253 | data->ext_power_reg = OXYGEN_GPIO_DATA; | ||
254 | data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; | ||
255 | data->ext_power_bit = GPIO_D2X_EXT_POWER; | ||
256 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER); | ||
257 | xonar_d2_init(chip); | ||
258 | } | ||
259 | |||
260 | static void update_cs4362a_volumes(struct oxygen *chip) | 260 | static void update_cs4362a_volumes(struct oxygen *chip) |
261 | { | 261 | { |
262 | u8 mute; | 262 | u8 mute; |
@@ -324,6 +324,11 @@ static void xonar_d1_init(struct oxygen *chip) | |||
324 | data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; | 324 | data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; |
325 | data->cs4362a_fm = CS4362A_FM_SINGLE | | 325 | data->cs4362a_fm = CS4362A_FM_SINGLE | |
326 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | 326 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; |
327 | if (data->model == MODEL_DX) { | ||
328 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
329 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
330 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
331 | } | ||
327 | 332 | ||
328 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 333 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, |
329 | OXYGEN_2WIRE_LENGTH_8 | | 334 | OXYGEN_2WIRE_LENGTH_8 | |
@@ -344,16 +349,6 @@ static void xonar_d1_init(struct oxygen *chip) | |||
344 | snd_component_add(chip->card, "CS5361"); | 349 | snd_component_add(chip->card, "CS5361"); |
345 | } | 350 | } |
346 | 351 | ||
347 | static void xonar_dx_init(struct oxygen *chip) | ||
348 | { | ||
349 | struct xonar_data *data = chip->model_data; | ||
350 | |||
351 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
352 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
353 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
354 | xonar_d1_init(chip); | ||
355 | } | ||
356 | |||
357 | static void xonar_cleanup(struct oxygen *chip) | 352 | static void xonar_cleanup(struct oxygen *chip) |
358 | { | 353 | { |
359 | struct xonar_data *data = chip->model_data; | 354 | struct xonar_data *data = chip->model_data; |
@@ -552,7 +547,7 @@ static int xonar_d1_control_filter(struct snd_kcontrol_new *template) | |||
552 | return 0; | 547 | return 0; |
553 | } | 548 | } |
554 | 549 | ||
555 | static int xonar_mixer_init(struct oxygen *chip) | 550 | static int xonar_d2_mixer_init(struct oxygen *chip) |
556 | { | 551 | { |
557 | return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | 552 | return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); |
558 | } | 553 | } |
@@ -562,130 +557,90 @@ static int xonar_d1_mixer_init(struct oxygen *chip) | |||
562 | return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); | 557 | return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); |
563 | } | 558 | } |
564 | 559 | ||
565 | static const struct oxygen_model xonar_models[] = { | 560 | static int xonar_model_probe(struct oxygen *chip, unsigned long driver_data) |
566 | [MODEL_D2] = { | 561 | { |
567 | .shortname = "Xonar D2", | 562 | static const char *const names[] = { |
568 | .longname = "Asus Virtuoso 200", | 563 | [MODEL_D1] = "Xonar D1", |
569 | .chip = "AV200", | 564 | [MODEL_DX] = "Xonar DX", |
570 | .owner = THIS_MODULE, | 565 | [MODEL_D2] = "Xonar D2", |
571 | .init = xonar_d2_init, | 566 | [MODEL_D2X] = "Xonar D2X", |
572 | .control_filter = xonar_d2_control_filter, | 567 | }; |
573 | .mixer_init = xonar_mixer_init, | 568 | struct xonar_data *data = chip->model_data; |
574 | .cleanup = xonar_cleanup, | 569 | |
575 | .suspend = xonar_cleanup, | 570 | data->model = driver_data; |
576 | .resume = xonar_d2_resume, | 571 | chip->model.shortname = names[data->model]; |
577 | .set_dac_params = set_pcm1796_params, | 572 | return 0; |
578 | .set_adc_params = set_cs53x1_params, | 573 | } |
579 | .update_dac_volume = update_pcm1796_volume, | 574 | |
580 | .update_dac_mute = update_pcm1796_mute, | 575 | static const struct oxygen_model model_xonar_d2 = { |
581 | .dac_tlv = pcm1796_db_scale, | 576 | .longname = "Asus Virtuoso 200", |
582 | .model_data_size = sizeof(struct xonar_data), | 577 | .chip = "AV200", |
583 | .pcm_dev_cfg = PLAYBACK_0_TO_I2S | | 578 | .owner = THIS_MODULE, |
584 | PLAYBACK_1_TO_SPDIF | | 579 | .probe = xonar_model_probe, |
585 | CAPTURE_0_FROM_I2S_2 | | 580 | .init = xonar_d2_init, |
586 | CAPTURE_1_FROM_SPDIF, | 581 | .control_filter = xonar_d2_control_filter, |
587 | .dac_channels = 8, | 582 | .mixer_init = xonar_d2_mixer_init, |
588 | .dac_volume_min = 0x0f, | 583 | .cleanup = xonar_cleanup, |
589 | .dac_volume_max = 0xff, | 584 | .suspend = xonar_cleanup, |
590 | .misc_flags = OXYGEN_MISC_MIDI, | 585 | .resume = xonar_d2_resume, |
591 | .function_flags = OXYGEN_FUNCTION_SPI | | 586 | .set_dac_params = set_pcm1796_params, |
592 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, | 587 | .set_adc_params = set_cs53x1_params, |
593 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 588 | .update_dac_volume = update_pcm1796_volume, |
594 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 589 | .update_dac_mute = update_pcm1796_mute, |
595 | }, | 590 | .dac_tlv = pcm1796_db_scale, |
596 | [MODEL_D2X] = { | 591 | .model_data_size = sizeof(struct xonar_data), |
597 | .shortname = "Xonar D2X", | 592 | .pcm_dev_cfg = PLAYBACK_0_TO_I2S | |
598 | .longname = "Asus Virtuoso 200", | 593 | PLAYBACK_1_TO_SPDIF | |
599 | .chip = "AV200", | 594 | CAPTURE_0_FROM_I2S_2 | |
600 | .owner = THIS_MODULE, | 595 | CAPTURE_1_FROM_SPDIF, |
601 | .init = xonar_d2x_init, | 596 | .dac_channels = 8, |
602 | .control_filter = xonar_d2_control_filter, | 597 | .dac_volume_min = 0x0f, |
603 | .mixer_init = xonar_mixer_init, | 598 | .dac_volume_max = 0xff, |
604 | .cleanup = xonar_cleanup, | 599 | .misc_flags = OXYGEN_MISC_MIDI, |
605 | .suspend = xonar_cleanup, | 600 | .function_flags = OXYGEN_FUNCTION_SPI | |
606 | .resume = xonar_d2_resume, | 601 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, |
607 | .set_dac_params = set_pcm1796_params, | 602 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
608 | .set_adc_params = set_cs53x1_params, | 603 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
609 | .update_dac_volume = update_pcm1796_volume, | 604 | }; |
610 | .update_dac_mute = update_pcm1796_mute, | 605 | |
611 | .gpio_changed = xonar_gpio_changed, | 606 | static const struct oxygen_model model_xonar_d1 = { |
612 | .dac_tlv = pcm1796_db_scale, | 607 | .longname = "Asus Virtuoso 100", |
613 | .model_data_size = sizeof(struct xonar_data), | 608 | .chip = "AV200", |
614 | .pcm_dev_cfg = PLAYBACK_0_TO_I2S | | 609 | .owner = THIS_MODULE, |
615 | PLAYBACK_1_TO_SPDIF | | 610 | .probe = xonar_model_probe, |
616 | CAPTURE_0_FROM_I2S_2 | | 611 | .init = xonar_d1_init, |
617 | CAPTURE_1_FROM_SPDIF, | 612 | .control_filter = xonar_d1_control_filter, |
618 | .dac_channels = 8, | 613 | .mixer_init = xonar_d1_mixer_init, |
619 | .dac_volume_min = 0x0f, | 614 | .cleanup = xonar_d1_cleanup, |
620 | .dac_volume_max = 0xff, | 615 | .suspend = xonar_d1_cleanup, |
621 | .misc_flags = OXYGEN_MISC_MIDI, | 616 | .resume = xonar_d1_resume, |
622 | .function_flags = OXYGEN_FUNCTION_SPI | | 617 | .set_dac_params = set_cs43xx_params, |
623 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, | 618 | .set_adc_params = set_cs53x1_params, |
624 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 619 | .update_dac_volume = update_cs43xx_volume, |
625 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 620 | .update_dac_mute = update_cs43xx_mute, |
626 | }, | 621 | .ac97_switch = xonar_d1_ac97_switch, |
627 | [MODEL_D1] = { | 622 | .dac_tlv = cs4362a_db_scale, |
628 | .shortname = "Xonar D1", | 623 | .model_data_size = sizeof(struct xonar_data), |
629 | .longname = "Asus Virtuoso 100", | 624 | .pcm_dev_cfg = PLAYBACK_0_TO_I2S | |
630 | .chip = "AV200", | 625 | PLAYBACK_1_TO_SPDIF | |
631 | .owner = THIS_MODULE, | 626 | CAPTURE_0_FROM_I2S_2, |
632 | .init = xonar_d1_init, | 627 | .dac_channels = 8, |
633 | .control_filter = xonar_d1_control_filter, | 628 | .dac_volume_min = 0, |
634 | .mixer_init = xonar_d1_mixer_init, | 629 | .dac_volume_max = 127, |
635 | .cleanup = xonar_d1_cleanup, | 630 | .function_flags = OXYGEN_FUNCTION_2WIRE, |
636 | .suspend = xonar_d1_cleanup, | 631 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
637 | .resume = xonar_d1_resume, | 632 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
638 | .set_dac_params = set_cs43xx_params, | ||
639 | .set_adc_params = set_cs53x1_params, | ||
640 | .update_dac_volume = update_cs43xx_volume, | ||
641 | .update_dac_mute = update_cs43xx_mute, | ||
642 | .ac97_switch = xonar_d1_ac97_switch, | ||
643 | .dac_tlv = cs4362a_db_scale, | ||
644 | .model_data_size = sizeof(struct xonar_data), | ||
645 | .pcm_dev_cfg = PLAYBACK_0_TO_I2S | | ||
646 | PLAYBACK_1_TO_SPDIF | | ||
647 | CAPTURE_0_FROM_I2S_2, | ||
648 | .dac_channels = 8, | ||
649 | .dac_volume_min = 0, | ||
650 | .dac_volume_max = 127, | ||
651 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
652 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
653 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
654 | }, | ||
655 | [MODEL_DX] = { | ||
656 | .shortname = "Xonar DX", | ||
657 | .longname = "Asus Virtuoso 100", | ||
658 | .chip = "AV200", | ||
659 | .owner = THIS_MODULE, | ||
660 | .init = xonar_dx_init, | ||
661 | .control_filter = xonar_d1_control_filter, | ||
662 | .mixer_init = xonar_d1_mixer_init, | ||
663 | .cleanup = xonar_d1_cleanup, | ||
664 | .suspend = xonar_d1_cleanup, | ||
665 | .resume = xonar_d1_resume, | ||
666 | .set_dac_params = set_cs43xx_params, | ||
667 | .set_adc_params = set_cs53x1_params, | ||
668 | .update_dac_volume = update_cs43xx_volume, | ||
669 | .update_dac_mute = update_cs43xx_mute, | ||
670 | .gpio_changed = xonar_gpio_changed, | ||
671 | .ac97_switch = xonar_d1_ac97_switch, | ||
672 | .dac_tlv = cs4362a_db_scale, | ||
673 | .model_data_size = sizeof(struct xonar_data), | ||
674 | .pcm_dev_cfg = PLAYBACK_0_TO_I2S | | ||
675 | PLAYBACK_1_TO_SPDIF | | ||
676 | CAPTURE_0_FROM_I2S_2, | ||
677 | .dac_channels = 8, | ||
678 | .dac_volume_min = 0, | ||
679 | .dac_volume_max = 127, | ||
680 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
681 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
682 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
683 | }, | ||
684 | }; | 633 | }; |
685 | 634 | ||
686 | static int __devinit xonar_probe(struct pci_dev *pci, | 635 | static int __devinit xonar_probe(struct pci_dev *pci, |
687 | const struct pci_device_id *pci_id) | 636 | const struct pci_device_id *pci_id) |
688 | { | 637 | { |
638 | static const struct oxygen_model *const models[] = { | ||
639 | [MODEL_D1] = &model_xonar_d1, | ||
640 | [MODEL_DX] = &model_xonar_d1, | ||
641 | [MODEL_D2] = &model_xonar_d2, | ||
642 | [MODEL_D2X] = &model_xonar_d2, | ||
643 | }; | ||
689 | static int dev; | 644 | static int dev; |
690 | int err; | 645 | int err; |
691 | 646 | ||
@@ -695,8 +650,10 @@ static int __devinit xonar_probe(struct pci_dev *pci, | |||
695 | ++dev; | 650 | ++dev; |
696 | return -ENOENT; | 651 | return -ENOENT; |
697 | } | 652 | } |
653 | BUG_ON(pci_id->driver_data >= ARRAY_SIZE(models)); | ||
698 | err = oxygen_pci_probe(pci, index[dev], id[dev], | 654 | err = oxygen_pci_probe(pci, index[dev], id[dev], |
699 | &xonar_models[pci_id->driver_data], 0); | 655 | models[pci_id->driver_data], |
656 | pci_id->driver_data); | ||
700 | if (err >= 0) | 657 | if (err >= 0) |
701 | ++dev; | 658 | ++dev; |
702 | return err; | 659 | return err; |