aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/oxygen/virtuoso.c
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2008-09-22 03:12:11 -0400
committerClemens Ladisch <clemens@ladisch.de>2008-09-22 03:12:11 -0400
commit7407a2e4b9e1fb3528bb355a571ee3eb7e32c386 (patch)
treeb7c0bfcf1ac51083dae93df64da3566cbcb82a1f /sound/pci/oxygen/virtuoso.c
parent79c50e23d4272404da7349010f514516976b447a (diff)
ALSA: virtuoso: add Xonar HDAV1.3 support
Add support for the Asus Xonar HDAV1.3 and the Xonar HDAV1.3 Deluxe. Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound/pci/oxygen/virtuoso.c')
-rw-r--r--sound/pci/oxygen/virtuoso.c251
1 files changed, 251 insertions, 0 deletions
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
103static struct pci_device_id xonar_ids[] __devinitdata = { 157static 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
145static void xonar_gpio_changed(struct oxygen *chip); 205static 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
248static 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
188static void xonar_enable_output(struct oxygen *chip) 266static 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
450static 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, &param);
475 param = 1;
476 hdmi_write_command(chip, 0x74, 1, &param);
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
372static void xonar_disable_output(struct oxygen *chip) 487static 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
506static void xonar_hdav_cleanup(struct oxygen *chip)
507{
508 u8 param = 0;
509
510 hdmi_write_command(chip, 0x74, 1, &param);
511 xonar_disable_output(chip);
512}
513
391static void xonar_d2_suspend(struct oxygen *chip) 514static 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
524static void xonar_hdav_suspend(struct oxygen *chip)
525{
526 xonar_hdav_cleanup(chip);
527 msleep(2);
528}
529
401static void xonar_d2_resume(struct oxygen *chip) 530static 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
542static 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, &param);
550 param = 1;
551 hdmi_write_command(chip, 0x74, 1, &param);
552 hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
553 pcm1796_init(chip);
554 xonar_enable_output(chip);
555}
556
557static 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
413static void set_pcm1796_params(struct oxygen *chip, 569static 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
619static 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
648static 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
463static void xonar_gpio_changed(struct oxygen *chip) 655static 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
674static 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
482static int gpio_bit_switch_get(struct snd_kcontrol *ctl, 686static 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
878static 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
657static int __devinit xonar_probe(struct pci_dev *pci, 907static 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;