diff options
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/Kconfig | 3 | ||||
-rw-r--r-- | sound/pci/oxygen/virtuoso.c | 251 |
2 files changed, 253 insertions, 1 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 4a7ebbc96762..1f8b7966a839 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -857,7 +857,8 @@ config SND_VIRTUOSO | |||
857 | select SND_OXYGEN_LIB | 857 | select SND_OXYGEN_LIB |
858 | help | 858 | help |
859 | Say Y here to include support for sound cards based on the | 859 | Say Y here to include support for sound cards based on the |
860 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2 and D2X. | 860 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X and |
861 | HDAV1.3 (Deluxe). | ||
861 | 862 | ||
862 | To compile this driver as a module, choose M here: the module | 863 | To compile this driver as a module, choose M here: the module |
863 | will be called snd-virtuoso. | 864 | will be called snd-virtuoso. |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 928283de6f37..98c6a8c65d81 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -62,14 +62,66 @@ | |||
62 | * AD0 <- 0 | 62 | * AD0 <- 0 |
63 | */ | 63 | */ |
64 | 64 | ||
65 | /* | ||
66 | * Xonar HDAV1.3 (Deluxe) | ||
67 | * ---------------------- | ||
68 | * | ||
69 | * CMI8788: | ||
70 | * | ||
71 | * I²C <-> PCM1796 (front) | ||
72 | * | ||
73 | * GPI 0 <- external power present | ||
74 | * | ||
75 | * GPIO 0 -> enable output to speakers | ||
76 | * GPIO 2 -> M0 of CS5381 | ||
77 | * GPIO 3 -> M1 of CS5381 | ||
78 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
79 | * | ||
80 | * TXD -> HDMI controller | ||
81 | * RXD <- HDMI controller | ||
82 | * | ||
83 | * PCM1796 front: AD1,0 <- 0,0 | ||
84 | * | ||
85 | * no daughterboard | ||
86 | * ---------------- | ||
87 | * | ||
88 | * GPIO 4 <- 1 | ||
89 | * | ||
90 | * H6 daughterboard | ||
91 | * ---------------- | ||
92 | * | ||
93 | * GPIO 4 <- 0 | ||
94 | * GPIO 5 <- 0 | ||
95 | * | ||
96 | * I²C <-> PCM1796 (surround) | ||
97 | * <-> PCM1796 (center/LFE) | ||
98 | * <-> PCM1796 (back) | ||
99 | * | ||
100 | * PCM1796 surround: AD1,0 <- 0,1 | ||
101 | * PCM1796 center/LFE: AD1,0 <- 1,0 | ||
102 | * PCM1796 back: AD1,0 <- 1,1 | ||
103 | * | ||
104 | * unknown daughterboard | ||
105 | * --------------------- | ||
106 | * | ||
107 | * GPIO 4 <- 0 | ||
108 | * GPIO 5 <- 1 | ||
109 | * | ||
110 | * I²C <-> CS4362A (surround, center/LFE, back) | ||
111 | * | ||
112 | * CS4362A: AD0 <- 0 | ||
113 | */ | ||
114 | |||
65 | #include <linux/pci.h> | 115 | #include <linux/pci.h> |
66 | #include <linux/delay.h> | 116 | #include <linux/delay.h> |
67 | #include <linux/mutex.h> | 117 | #include <linux/mutex.h> |
68 | #include <sound/ac97_codec.h> | 118 | #include <sound/ac97_codec.h> |
119 | #include <sound/asoundef.h> | ||
69 | #include <sound/control.h> | 120 | #include <sound/control.h> |
70 | #include <sound/core.h> | 121 | #include <sound/core.h> |
71 | #include <sound/initval.h> | 122 | #include <sound/initval.h> |
72 | #include <sound/pcm.h> | 123 | #include <sound/pcm.h> |
124 | #include <sound/pcm_params.h> | ||
73 | #include <sound/tlv.h> | 125 | #include <sound/tlv.h> |
74 | #include "oxygen.h" | 126 | #include "oxygen.h" |
75 | #include "cm9780.h" | 127 | #include "cm9780.h" |
@@ -98,12 +150,15 @@ enum { | |||
98 | MODEL_D2X, | 150 | MODEL_D2X, |
99 | MODEL_D1, | 151 | MODEL_D1, |
100 | MODEL_DX, | 152 | MODEL_DX, |
153 | MODEL_HDAV, /* without daughterboard */ | ||
154 | MODEL_HDAV_H6, /* with H6 daughterboard */ | ||
101 | }; | 155 | }; |
102 | 156 | ||
103 | static struct pci_device_id xonar_ids[] __devinitdata = { | 157 | static struct pci_device_id xonar_ids[] __devinitdata = { |
104 | { OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 }, | 158 | { OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 }, |
105 | { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX }, | 159 | { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX }, |
106 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, | 160 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, |
161 | { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, | ||
107 | { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, | 162 | { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, |
108 | { } | 163 | { } |
109 | }; | 164 | }; |
@@ -124,6 +179,10 @@ MODULE_DEVICE_TABLE(pci, xonar_ids); | |||
124 | #define GPIO_DX_FRONT_PANEL 0x0002 | 179 | #define GPIO_DX_FRONT_PANEL 0x0002 |
125 | #define GPIO_DX_INPUT_ROUTE 0x0100 | 180 | #define GPIO_DX_INPUT_ROUTE 0x0100 |
126 | 181 | ||
182 | #define GPIO_HDAV_DB_MASK 0x0030 | ||
183 | #define GPIO_HDAV_DB_H6 0x0000 | ||
184 | #define GPIO_HDAV_DB_XX 0x0020 | ||
185 | |||
127 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ADx=i, /W=0 */ | 186 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ADx=i, /W=0 */ |
128 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ | 187 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ |
129 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ | 188 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ |
@@ -140,6 +199,7 @@ struct xonar_data { | |||
140 | u8 pcm1796_oversampling; | 199 | u8 pcm1796_oversampling; |
141 | u8 cs4398_fm; | 200 | u8 cs4398_fm; |
142 | u8 cs4362a_fm; | 201 | u8 cs4362a_fm; |
202 | u8 hdmi_params[5]; | ||
143 | }; | 203 | }; |
144 | 204 | ||
145 | static void xonar_gpio_changed(struct oxygen *chip); | 205 | static void xonar_gpio_changed(struct oxygen *chip); |
@@ -185,6 +245,24 @@ static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) | |||
185 | oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); | 245 | oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); |
186 | } | 246 | } |
187 | 247 | ||
248 | static void hdmi_write_command(struct oxygen *chip, u8 command, | ||
249 | unsigned int count, const u8 *params) | ||
250 | { | ||
251 | unsigned int i; | ||
252 | u8 checksum; | ||
253 | |||
254 | oxygen_write_uart(chip, 0xfb); | ||
255 | oxygen_write_uart(chip, 0xef); | ||
256 | oxygen_write_uart(chip, command); | ||
257 | oxygen_write_uart(chip, count); | ||
258 | for (i = 0; i < count; ++i) | ||
259 | oxygen_write_uart(chip, params[i]); | ||
260 | checksum = 0xfb + 0xef + command + count; | ||
261 | for (i = 0; i < count; ++i) | ||
262 | checksum += params[i]; | ||
263 | oxygen_write_uart(chip, checksum); | ||
264 | } | ||
265 | |||
188 | static void xonar_enable_output(struct oxygen *chip) | 266 | static void xonar_enable_output(struct oxygen *chip) |
189 | { | 267 | { |
190 | struct xonar_data *data = chip->model_data; | 268 | struct xonar_data *data = chip->model_data; |
@@ -369,6 +447,43 @@ static void xonar_d1_init(struct oxygen *chip) | |||
369 | snd_component_add(chip->card, "CS5361"); | 447 | snd_component_add(chip->card, "CS5361"); |
370 | } | 448 | } |
371 | 449 | ||
450 | static void xonar_hdav_init(struct oxygen *chip) | ||
451 | { | ||
452 | struct xonar_data *data = chip->model_data; | ||
453 | u8 param; | ||
454 | |||
455 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
456 | OXYGEN_2WIRE_LENGTH_8 | | ||
457 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
458 | OXYGEN_2WIRE_SPEED_FAST); | ||
459 | |||
460 | data->anti_pop_delay = 100; | ||
461 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; | ||
462 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
463 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
464 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
465 | data->pcm1796_oversampling = PCM1796_OS_64; | ||
466 | |||
467 | pcm1796_init(chip); | ||
468 | |||
469 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DX_INPUT_ROUTE); | ||
470 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DX_INPUT_ROUTE); | ||
471 | |||
472 | oxygen_reset_uart(chip); | ||
473 | param = 0; | ||
474 | hdmi_write_command(chip, 0x61, 1, ¶m); | ||
475 | param = 1; | ||
476 | hdmi_write_command(chip, 0x74, 1, ¶m); | ||
477 | data->hdmi_params[1] = IEC958_AES3_CON_FS_48000; | ||
478 | data->hdmi_params[4] = 1; | ||
479 | hdmi_write_command(chip, 0x54, 5, data->hdmi_params); | ||
480 | |||
481 | xonar_common_init(chip); | ||
482 | |||
483 | snd_component_add(chip->card, "PCM1796"); | ||
484 | snd_component_add(chip->card, "CS5381"); | ||
485 | } | ||
486 | |||
372 | static void xonar_disable_output(struct oxygen *chip) | 487 | static void xonar_disable_output(struct oxygen *chip) |
373 | { | 488 | { |
374 | struct xonar_data *data = chip->model_data; | 489 | struct xonar_data *data = chip->model_data; |
@@ -388,6 +503,14 @@ static void xonar_d1_cleanup(struct oxygen *chip) | |||
388 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); | 503 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); |
389 | } | 504 | } |
390 | 505 | ||
506 | static void xonar_hdav_cleanup(struct oxygen *chip) | ||
507 | { | ||
508 | u8 param = 0; | ||
509 | |||
510 | hdmi_write_command(chip, 0x74, 1, ¶m); | ||
511 | xonar_disable_output(chip); | ||
512 | } | ||
513 | |||
391 | static void xonar_d2_suspend(struct oxygen *chip) | 514 | static void xonar_d2_suspend(struct oxygen *chip) |
392 | { | 515 | { |
393 | xonar_d2_cleanup(chip); | 516 | xonar_d2_cleanup(chip); |
@@ -398,6 +521,12 @@ static void xonar_d1_suspend(struct oxygen *chip) | |||
398 | xonar_d1_cleanup(chip); | 521 | xonar_d1_cleanup(chip); |
399 | } | 522 | } |
400 | 523 | ||
524 | static void xonar_hdav_suspend(struct oxygen *chip) | ||
525 | { | ||
526 | xonar_hdav_cleanup(chip); | ||
527 | msleep(2); | ||
528 | } | ||
529 | |||
401 | static void xonar_d2_resume(struct oxygen *chip) | 530 | static void xonar_d2_resume(struct oxygen *chip) |
402 | { | 531 | { |
403 | pcm1796_init(chip); | 532 | pcm1796_init(chip); |
@@ -410,6 +539,33 @@ static void xonar_d1_resume(struct oxygen *chip) | |||
410 | xonar_enable_output(chip); | 539 | xonar_enable_output(chip); |
411 | } | 540 | } |
412 | 541 | ||
542 | static void xonar_hdav_resume(struct oxygen *chip) | ||
543 | { | ||
544 | struct xonar_data *data = chip->model_data; | ||
545 | u8 param; | ||
546 | |||
547 | oxygen_reset_uart(chip); | ||
548 | param = 0; | ||
549 | hdmi_write_command(chip, 0x61, 1, ¶m); | ||
550 | param = 1; | ||
551 | hdmi_write_command(chip, 0x74, 1, ¶m); | ||
552 | hdmi_write_command(chip, 0x54, 5, data->hdmi_params); | ||
553 | pcm1796_init(chip); | ||
554 | xonar_enable_output(chip); | ||
555 | } | ||
556 | |||
557 | static void xonar_hdav_pcm_hardware_filter(unsigned int channel, | ||
558 | struct snd_pcm_hardware *hardware) | ||
559 | { | ||
560 | if (channel == PCM_MULTICH) { | ||
561 | hardware->rates = SNDRV_PCM_RATE_44100 | | ||
562 | SNDRV_PCM_RATE_48000 | | ||
563 | SNDRV_PCM_RATE_96000 | | ||
564 | SNDRV_PCM_RATE_192000; | ||
565 | hardware->rate_min = 44100; | ||
566 | } | ||
567 | } | ||
568 | |||
413 | static void set_pcm1796_params(struct oxygen *chip, | 569 | static void set_pcm1796_params(struct oxygen *chip, |
414 | struct snd_pcm_hw_params *params) | 570 | struct snd_pcm_hw_params *params) |
415 | { | 571 | { |
@@ -460,6 +616,42 @@ static void set_cs43xx_params(struct oxygen *chip, | |||
460 | cs4362a_write(chip, 0x0c, data->cs4362a_fm); | 616 | cs4362a_write(chip, 0x0c, data->cs4362a_fm); |
461 | } | 617 | } |
462 | 618 | ||
619 | static void set_hdmi_params(struct oxygen *chip, | ||
620 | struct snd_pcm_hw_params *params) | ||
621 | { | ||
622 | struct xonar_data *data = chip->model_data; | ||
623 | |||
624 | data->hdmi_params[0] = 0; /* 1 = non-audio */ | ||
625 | switch (params_rate(params)) { | ||
626 | case 44100: | ||
627 | data->hdmi_params[1] = IEC958_AES3_CON_FS_44100; | ||
628 | break; | ||
629 | case 48000: | ||
630 | data->hdmi_params[1] = IEC958_AES3_CON_FS_48000; | ||
631 | break; | ||
632 | default: /* 96000 */ | ||
633 | data->hdmi_params[1] = IEC958_AES3_CON_FS_96000; | ||
634 | break; | ||
635 | case 192000: | ||
636 | data->hdmi_params[1] = IEC958_AES3_CON_FS_192000; | ||
637 | break; | ||
638 | } | ||
639 | data->hdmi_params[2] = params_channels(params) / 2 - 1; | ||
640 | if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) | ||
641 | data->hdmi_params[3] = 0; | ||
642 | else | ||
643 | data->hdmi_params[3] = 0xc0; | ||
644 | data->hdmi_params[4] = 1; /* ? */ | ||
645 | hdmi_write_command(chip, 0x54, 5, data->hdmi_params); | ||
646 | } | ||
647 | |||
648 | static void set_hdav_params(struct oxygen *chip, | ||
649 | struct snd_pcm_hw_params *params) | ||
650 | { | ||
651 | set_pcm1796_params(chip, params); | ||
652 | set_hdmi_params(chip, params); | ||
653 | } | ||
654 | |||
463 | static void xonar_gpio_changed(struct oxygen *chip) | 655 | static void xonar_gpio_changed(struct oxygen *chip) |
464 | { | 656 | { |
465 | struct xonar_data *data = chip->model_data; | 657 | struct xonar_data *data = chip->model_data; |
@@ -479,6 +671,18 @@ static void xonar_gpio_changed(struct oxygen *chip) | |||
479 | } | 671 | } |
480 | } | 672 | } |
481 | 673 | ||
674 | static void xonar_hdav_uart_input(struct oxygen *chip) | ||
675 | { | ||
676 | if (chip->uart_input_count >= 2 && | ||
677 | chip->uart_input[chip->uart_input_count - 2] == 'O' && | ||
678 | chip->uart_input[chip->uart_input_count - 1] == 'K') { | ||
679 | printk(KERN_DEBUG "message from Xonar HDAV HDMI chip received:"); | ||
680 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
681 | chip->uart_input, chip->uart_input_count); | ||
682 | chip->uart_input_count = 0; | ||
683 | } | ||
684 | } | ||
685 | |||
482 | static int gpio_bit_switch_get(struct snd_kcontrol *ctl, | 686 | static int gpio_bit_switch_get(struct snd_kcontrol *ctl, |
483 | struct snd_ctl_elem_value *value) | 687 | struct snd_ctl_elem_value *value) |
484 | { | 688 | { |
@@ -576,16 +780,33 @@ static int xonar_model_probe(struct oxygen *chip, unsigned long driver_data) | |||
576 | [MODEL_DX] = "Xonar DX", | 780 | [MODEL_DX] = "Xonar DX", |
577 | [MODEL_D2] = "Xonar D2", | 781 | [MODEL_D2] = "Xonar D2", |
578 | [MODEL_D2X] = "Xonar D2X", | 782 | [MODEL_D2X] = "Xonar D2X", |
783 | [MODEL_HDAV] = "Xonar HDAV1.3", | ||
784 | [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", | ||
579 | }; | 785 | }; |
580 | static const u8 dacs[] = { | 786 | static const u8 dacs[] = { |
581 | [MODEL_D1] = 2, | 787 | [MODEL_D1] = 2, |
582 | [MODEL_DX] = 2, | 788 | [MODEL_DX] = 2, |
583 | [MODEL_D2] = 4, | 789 | [MODEL_D2] = 4, |
584 | [MODEL_D2X] = 4, | 790 | [MODEL_D2X] = 4, |
791 | [MODEL_HDAV] = 1, | ||
792 | [MODEL_HDAV_H6] = 4, | ||
585 | }; | 793 | }; |
586 | struct xonar_data *data = chip->model_data; | 794 | struct xonar_data *data = chip->model_data; |
587 | 795 | ||
588 | data->model = driver_data; | 796 | data->model = driver_data; |
797 | if (data->model == MODEL_HDAV) { | ||
798 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
799 | GPIO_HDAV_DB_MASK); | ||
800 | switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
801 | GPIO_HDAV_DB_MASK) { | ||
802 | case GPIO_HDAV_DB_H6: | ||
803 | data->model = MODEL_HDAV_H6; | ||
804 | break; | ||
805 | case GPIO_HDAV_DB_XX: | ||
806 | snd_printk(KERN_ERR "unknown daughterboard\n"); | ||
807 | return -ENODEV; | ||
808 | } | ||
809 | } | ||
589 | 810 | ||
590 | data->dacs = dacs[data->model]; | 811 | data->dacs = dacs[data->model]; |
591 | chip->model.shortname = names[data->model]; | 812 | chip->model.shortname = names[data->model]; |
@@ -654,6 +875,35 @@ static const struct oxygen_model model_xonar_d1 = { | |||
654 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 875 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
655 | }; | 876 | }; |
656 | 877 | ||
878 | static const struct oxygen_model model_xonar_hdav = { | ||
879 | .longname = "Asus Virtuoso 200", | ||
880 | .chip = "AV200", | ||
881 | .owner = THIS_MODULE, | ||
882 | .probe = xonar_model_probe, | ||
883 | .init = xonar_hdav_init, | ||
884 | .cleanup = xonar_hdav_cleanup, | ||
885 | .suspend = xonar_hdav_suspend, | ||
886 | .resume = xonar_hdav_resume, | ||
887 | .pcm_hardware_filter = xonar_hdav_pcm_hardware_filter, | ||
888 | .set_dac_params = set_hdav_params, | ||
889 | .set_adc_params = set_cs53x1_params, | ||
890 | .update_dac_volume = update_pcm1796_volume, | ||
891 | .update_dac_mute = update_pcm1796_mute, | ||
892 | .uart_input = xonar_hdav_uart_input, | ||
893 | .ac97_switch = xonar_line_mic_ac97_switch, | ||
894 | .dac_tlv = pcm1796_db_scale, | ||
895 | .model_data_size = sizeof(struct xonar_data), | ||
896 | .device_config = PLAYBACK_0_TO_I2S | | ||
897 | PLAYBACK_1_TO_SPDIF | | ||
898 | CAPTURE_0_FROM_I2S_2, | ||
899 | .dac_channels = 8, | ||
900 | .dac_volume_min = 0x0f, | ||
901 | .dac_volume_max = 0xff, | ||
902 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
903 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
904 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
905 | }; | ||
906 | |||
657 | static int __devinit xonar_probe(struct pci_dev *pci, | 907 | static int __devinit xonar_probe(struct pci_dev *pci, |
658 | const struct pci_device_id *pci_id) | 908 | const struct pci_device_id *pci_id) |
659 | { | 909 | { |
@@ -662,6 +912,7 @@ static int __devinit xonar_probe(struct pci_dev *pci, | |||
662 | [MODEL_DX] = &model_xonar_d1, | 912 | [MODEL_DX] = &model_xonar_d1, |
663 | [MODEL_D2] = &model_xonar_d2, | 913 | [MODEL_D2] = &model_xonar_d2, |
664 | [MODEL_D2X] = &model_xonar_d2, | 914 | [MODEL_D2X] = &model_xonar_d2, |
915 | [MODEL_HDAV] = &model_xonar_hdav, | ||
665 | }; | 916 | }; |
666 | static int dev; | 917 | static int dev; |
667 | int err; | 918 | int err; |