diff options
Diffstat (limited to 'sound/pci/oxygen/xonar_wm87x6.c')
-rw-r--r-- | sound/pci/oxygen/xonar_wm87x6.c | 317 |
1 files changed, 273 insertions, 44 deletions
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 200f7601276f..42d1ab136217 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * card driver for models with WM8776/WM8766 DACs (Xonar DS) | 2 | * card driver for models with WM8776/WM8766 DACs (Xonar DS/HDAV1.3 Slim) |
3 | * | 3 | * |
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
5 | * | 5 | * |
@@ -22,26 +22,48 @@ | |||
22 | * | 22 | * |
23 | * CMI8788: | 23 | * CMI8788: |
24 | * | 24 | * |
25 | * SPI 0 -> WM8766 (surround, center/LFE, back) | 25 | * SPI 0 -> WM8766 (surround, center/LFE, back) |
26 | * SPI 1 -> WM8776 (front, input) | 26 | * SPI 1 -> WM8776 (front, input) |
27 | * | 27 | * |
28 | * GPIO 4 <- headphone detect, 0 = plugged | 28 | * GPIO 4 <- headphone detect, 0 = plugged |
29 | * GPIO 6 -> route input jack to mic-in (0) or line-in (1) | 29 | * GPIO 6 -> route input jack to mic-in (0) or line-in (1) |
30 | * GPIO 7 -> enable output to front L/R speaker channels | 30 | * GPIO 7 -> enable output to front L/R speaker channels |
31 | * GPIO 8 -> enable output to other speaker channels and front panel headphone | 31 | * GPIO 8 -> enable output to other speaker channels and front panel headphone |
32 | * | 32 | * |
33 | * WM8766: | 33 | * WM8776: |
34 | * | 34 | * |
35 | * input 1 <- line | 35 | * input 1 <- line |
36 | * input 2 <- mic | 36 | * input 2 <- mic |
37 | * input 3 <- front mic | 37 | * input 3 <- front mic |
38 | * input 4 <- aux | 38 | * input 4 <- aux |
39 | */ | ||
40 | |||
41 | /* | ||
42 | * Xonar HDAV1.3 Slim | ||
43 | * ------------------ | ||
44 | * | ||
45 | * CMI8788: | ||
46 | * | ||
47 | * I²C <-> WM8776 (addr 0011010) | ||
48 | * | ||
49 | * GPIO 0 -> disable HDMI output | ||
50 | * GPIO 1 -> enable HP output | ||
51 | * GPIO 6 -> firmware EEPROM I²C clock | ||
52 | * GPIO 7 <-> firmware EEPROM I²C data | ||
53 | * | ||
54 | * UART <-> HDMI controller | ||
55 | * | ||
56 | * WM8776: | ||
57 | * | ||
58 | * input 1 <- mic | ||
59 | * input 2 <- aux | ||
39 | */ | 60 | */ |
40 | 61 | ||
41 | #include <linux/pci.h> | 62 | #include <linux/pci.h> |
42 | #include <linux/delay.h> | 63 | #include <linux/delay.h> |
43 | #include <sound/control.h> | 64 | #include <sound/control.h> |
44 | #include <sound/core.h> | 65 | #include <sound/core.h> |
66 | #include <sound/info.h> | ||
45 | #include <sound/jack.h> | 67 | #include <sound/jack.h> |
46 | #include <sound/pcm.h> | 68 | #include <sound/pcm.h> |
47 | #include <sound/pcm_params.h> | 69 | #include <sound/pcm_params.h> |
@@ -55,6 +77,13 @@ | |||
55 | #define GPIO_DS_OUTPUT_FRONTLR 0x0080 | 77 | #define GPIO_DS_OUTPUT_FRONTLR 0x0080 |
56 | #define GPIO_DS_OUTPUT_ENABLE 0x0100 | 78 | #define GPIO_DS_OUTPUT_ENABLE 0x0100 |
57 | 79 | ||
80 | #define GPIO_SLIM_HDMI_DISABLE 0x0001 | ||
81 | #define GPIO_SLIM_OUTPUT_ENABLE 0x0002 | ||
82 | #define GPIO_SLIM_FIRMWARE_CLK 0x0040 | ||
83 | #define GPIO_SLIM_FIRMWARE_DATA 0x0080 | ||
84 | |||
85 | #define I2C_DEVICE_WM8776 0x34 /* 001101, 0, /W=0 */ | ||
86 | |||
58 | #define LC_CONTROL_LIMITER 0x40000000 | 87 | #define LC_CONTROL_LIMITER 0x40000000 |
59 | #define LC_CONTROL_ALC 0x20000000 | 88 | #define LC_CONTROL_ALC 0x20000000 |
60 | 89 | ||
@@ -66,19 +95,37 @@ struct xonar_wm87x6 { | |||
66 | struct snd_kcontrol *mic_adcmux_control; | 95 | struct snd_kcontrol *mic_adcmux_control; |
67 | struct snd_kcontrol *lc_controls[13]; | 96 | struct snd_kcontrol *lc_controls[13]; |
68 | struct snd_jack *hp_jack; | 97 | struct snd_jack *hp_jack; |
98 | struct xonar_hdmi hdmi; | ||
69 | }; | 99 | }; |
70 | 100 | ||
71 | static void wm8776_write(struct oxygen *chip, | 101 | static void wm8776_write_spi(struct oxygen *chip, |
72 | unsigned int reg, unsigned int value) | 102 | unsigned int reg, unsigned int value) |
73 | { | 103 | { |
74 | struct xonar_wm87x6 *data = chip->model_data; | ||
75 | |||
76 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | 104 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | |
77 | OXYGEN_SPI_DATA_LENGTH_2 | | 105 | OXYGEN_SPI_DATA_LENGTH_2 | |
78 | OXYGEN_SPI_CLOCK_160 | | 106 | OXYGEN_SPI_CLOCK_160 | |
79 | (1 << OXYGEN_SPI_CODEC_SHIFT) | | 107 | (1 << OXYGEN_SPI_CODEC_SHIFT) | |
80 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 108 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
81 | (reg << 9) | value); | 109 | (reg << 9) | value); |
110 | } | ||
111 | |||
112 | static void wm8776_write_i2c(struct oxygen *chip, | ||
113 | unsigned int reg, unsigned int value) | ||
114 | { | ||
115 | oxygen_write_i2c(chip, I2C_DEVICE_WM8776, | ||
116 | (reg << 1) | (value >> 8), value); | ||
117 | } | ||
118 | |||
119 | static void wm8776_write(struct oxygen *chip, | ||
120 | unsigned int reg, unsigned int value) | ||
121 | { | ||
122 | struct xonar_wm87x6 *data = chip->model_data; | ||
123 | |||
124 | if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) == | ||
125 | OXYGEN_FUNCTION_SPI) | ||
126 | wm8776_write_spi(chip, reg, value); | ||
127 | else | ||
128 | wm8776_write_i2c(chip, reg, value); | ||
82 | if (reg < ARRAY_SIZE(data->wm8776_regs)) { | 129 | if (reg < ARRAY_SIZE(data->wm8776_regs)) { |
83 | if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER) | 130 | if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER) |
84 | value &= ~WM8776_UPDATE; | 131 | value &= ~WM8776_UPDATE; |
@@ -245,17 +292,50 @@ static void xonar_ds_init(struct oxygen *chip) | |||
245 | snd_component_add(chip->card, "WM8766"); | 292 | snd_component_add(chip->card, "WM8766"); |
246 | } | 293 | } |
247 | 294 | ||
295 | static void xonar_hdav_slim_init(struct oxygen *chip) | ||
296 | { | ||
297 | struct xonar_wm87x6 *data = chip->model_data; | ||
298 | |||
299 | data->generic.anti_pop_delay = 300; | ||
300 | data->generic.output_enable_bit = GPIO_SLIM_OUTPUT_ENABLE; | ||
301 | |||
302 | wm8776_init(chip); | ||
303 | |||
304 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
305 | GPIO_SLIM_HDMI_DISABLE | | ||
306 | GPIO_SLIM_FIRMWARE_CLK | | ||
307 | GPIO_SLIM_FIRMWARE_DATA); | ||
308 | |||
309 | xonar_hdmi_init(chip, &data->hdmi); | ||
310 | xonar_enable_output(chip); | ||
311 | |||
312 | snd_component_add(chip->card, "WM8776"); | ||
313 | } | ||
314 | |||
248 | static void xonar_ds_cleanup(struct oxygen *chip) | 315 | static void xonar_ds_cleanup(struct oxygen *chip) |
249 | { | 316 | { |
250 | xonar_disable_output(chip); | 317 | xonar_disable_output(chip); |
251 | wm8776_write(chip, WM8776_RESET, 0); | 318 | wm8776_write(chip, WM8776_RESET, 0); |
252 | } | 319 | } |
253 | 320 | ||
321 | static void xonar_hdav_slim_cleanup(struct oxygen *chip) | ||
322 | { | ||
323 | xonar_hdmi_cleanup(chip); | ||
324 | xonar_disable_output(chip); | ||
325 | wm8776_write(chip, WM8776_RESET, 0); | ||
326 | msleep(2); | ||
327 | } | ||
328 | |||
254 | static void xonar_ds_suspend(struct oxygen *chip) | 329 | static void xonar_ds_suspend(struct oxygen *chip) |
255 | { | 330 | { |
256 | xonar_ds_cleanup(chip); | 331 | xonar_ds_cleanup(chip); |
257 | } | 332 | } |
258 | 333 | ||
334 | static void xonar_hdav_slim_suspend(struct oxygen *chip) | ||
335 | { | ||
336 | xonar_hdav_slim_cleanup(chip); | ||
337 | } | ||
338 | |||
259 | static void xonar_ds_resume(struct oxygen *chip) | 339 | static void xonar_ds_resume(struct oxygen *chip) |
260 | { | 340 | { |
261 | wm8776_registers_init(chip); | 341 | wm8776_registers_init(chip); |
@@ -264,6 +344,15 @@ static void xonar_ds_resume(struct oxygen *chip) | |||
264 | xonar_ds_handle_hp_jack(chip); | 344 | xonar_ds_handle_hp_jack(chip); |
265 | } | 345 | } |
266 | 346 | ||
347 | static void xonar_hdav_slim_resume(struct oxygen *chip) | ||
348 | { | ||
349 | struct xonar_wm87x6 *data = chip->model_data; | ||
350 | |||
351 | wm8776_registers_init(chip); | ||
352 | xonar_hdmi_resume(chip, &data->hdmi); | ||
353 | xonar_enable_output(chip); | ||
354 | } | ||
355 | |||
267 | static void wm8776_adc_hardware_filter(unsigned int channel, | 356 | static void wm8776_adc_hardware_filter(unsigned int channel, |
268 | struct snd_pcm_hardware *hardware) | 357 | struct snd_pcm_hardware *hardware) |
269 | { | 358 | { |
@@ -278,6 +367,13 @@ static void wm8776_adc_hardware_filter(unsigned int channel, | |||
278 | } | 367 | } |
279 | } | 368 | } |
280 | 369 | ||
370 | static void xonar_hdav_slim_hardware_filter(unsigned int channel, | ||
371 | struct snd_pcm_hardware *hardware) | ||
372 | { | ||
373 | wm8776_adc_hardware_filter(channel, hardware); | ||
374 | xonar_hdmi_pcm_hardware_filter(channel, hardware); | ||
375 | } | ||
376 | |||
281 | static void set_wm87x6_dac_params(struct oxygen *chip, | 377 | static void set_wm87x6_dac_params(struct oxygen *chip, |
282 | struct snd_pcm_hw_params *params) | 378 | struct snd_pcm_hw_params *params) |
283 | { | 379 | { |
@@ -294,6 +390,14 @@ static void set_wm8776_adc_params(struct oxygen *chip, | |||
294 | wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); | 390 | wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); |
295 | } | 391 | } |
296 | 392 | ||
393 | static void set_hdav_slim_dac_params(struct oxygen *chip, | ||
394 | struct snd_pcm_hw_params *params) | ||
395 | { | ||
396 | struct xonar_wm87x6 *data = chip->model_data; | ||
397 | |||
398 | xonar_set_hdmi_params(chip, &data->hdmi, params); | ||
399 | } | ||
400 | |||
297 | static void update_wm8776_volume(struct oxygen *chip) | 401 | static void update_wm8776_volume(struct oxygen *chip) |
298 | { | 402 | { |
299 | struct xonar_wm87x6 *data = chip->model_data; | 403 | struct xonar_wm87x6 *data = chip->model_data; |
@@ -473,11 +577,6 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, | |||
473 | const char *const *names; | 577 | const char *const *names; |
474 | 578 | ||
475 | max = (ctl->private_value >> 12) & 0xf; | 579 | max = (ctl->private_value >> 12) & 0xf; |
476 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
477 | info->count = 1; | ||
478 | info->value.enumerated.items = max + 1; | ||
479 | if (info->value.enumerated.item > max) | ||
480 | info->value.enumerated.item = max; | ||
481 | switch ((ctl->private_value >> 24) & 0x1f) { | 580 | switch ((ctl->private_value >> 24) & 0x1f) { |
482 | case WM8776_ALCCTRL2: | 581 | case WM8776_ALCCTRL2: |
483 | names = hld; | 582 | names = hld; |
@@ -501,8 +600,7 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, | |||
501 | default: | 600 | default: |
502 | return -ENXIO; | 601 | return -ENXIO; |
503 | } | 602 | } |
504 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | 603 | return snd_ctl_enum_info(info, 1, max + 1, names); |
505 | return 0; | ||
506 | } | 604 | } |
507 | 605 | ||
508 | static int wm8776_field_volume_info(struct snd_kcontrol *ctl, | 606 | static int wm8776_field_volume_info(struct snd_kcontrol *ctl, |
@@ -759,13 +857,8 @@ static int wm8776_level_control_info(struct snd_kcontrol *ctl, | |||
759 | static const char *const names[3] = { | 857 | static const char *const names[3] = { |
760 | "None", "Peak Limiter", "Automatic Level Control" | 858 | "None", "Peak Limiter", "Automatic Level Control" |
761 | }; | 859 | }; |
762 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 860 | |
763 | info->count = 1; | 861 | return snd_ctl_enum_info(info, 1, 3, names); |
764 | info->value.enumerated.items = 3; | ||
765 | if (info->value.enumerated.item >= 3) | ||
766 | info->value.enumerated.item = 2; | ||
767 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
768 | return 0; | ||
769 | } | 862 | } |
770 | 863 | ||
771 | static int wm8776_level_control_get(struct snd_kcontrol *ctl, | 864 | static int wm8776_level_control_get(struct snd_kcontrol *ctl, |
@@ -851,13 +944,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | |||
851 | "None", "High-pass Filter" | 944 | "None", "High-pass Filter" |
852 | }; | 945 | }; |
853 | 946 | ||
854 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 947 | return snd_ctl_enum_info(info, 1, 2, names); |
855 | info->count = 1; | ||
856 | info->value.enumerated.items = 2; | ||
857 | if (info->value.enumerated.item >= 2) | ||
858 | info->value.enumerated.item = 1; | ||
859 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
860 | return 0; | ||
861 | } | 948 | } |
862 | 949 | ||
863 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | 950 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) |
@@ -985,6 +1072,53 @@ static const struct snd_kcontrol_new ds_controls[] = { | |||
985 | .private_value = 0, | 1072 | .private_value = 0, |
986 | }, | 1073 | }, |
987 | }; | 1074 | }; |
1075 | static const struct snd_kcontrol_new hdav_slim_controls[] = { | ||
1076 | { | ||
1077 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1078 | .name = "HDMI Playback Switch", | ||
1079 | .info = snd_ctl_boolean_mono_info, | ||
1080 | .get = xonar_gpio_bit_switch_get, | ||
1081 | .put = xonar_gpio_bit_switch_put, | ||
1082 | .private_value = GPIO_SLIM_HDMI_DISABLE | XONAR_GPIO_BIT_INVERT, | ||
1083 | }, | ||
1084 | { | ||
1085 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1086 | .name = "Headphone Playback Volume", | ||
1087 | .info = wm8776_hp_vol_info, | ||
1088 | .get = wm8776_hp_vol_get, | ||
1089 | .put = wm8776_hp_vol_put, | ||
1090 | .tlv = { .p = wm8776_hp_db_scale }, | ||
1091 | }, | ||
1092 | WM8776_BIT_SWITCH("Headphone Playback Switch", | ||
1093 | WM8776_PWRDOWN, WM8776_HPPD, 1, 0), | ||
1094 | { | ||
1095 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1096 | .name = "Input Capture Volume", | ||
1097 | .info = wm8776_input_vol_info, | ||
1098 | .get = wm8776_input_vol_get, | ||
1099 | .put = wm8776_input_vol_put, | ||
1100 | .tlv = { .p = wm8776_adc_db_scale }, | ||
1101 | }, | ||
1102 | WM8776_BIT_SWITCH("Mic Capture Switch", | ||
1103 | WM8776_ADCMUX, 1 << 0, 0, 0), | ||
1104 | WM8776_BIT_SWITCH("Aux Capture Switch", | ||
1105 | WM8776_ADCMUX, 1 << 1, 0, 0), | ||
1106 | { | ||
1107 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1108 | .name = "ADC Filter Capture Enum", | ||
1109 | .info = hpf_info, | ||
1110 | .get = hpf_get, | ||
1111 | .put = hpf_put, | ||
1112 | }, | ||
1113 | { | ||
1114 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1115 | .name = "Level Control Capture Enum", | ||
1116 | .info = wm8776_level_control_info, | ||
1117 | .get = wm8776_level_control_get, | ||
1118 | .put = wm8776_level_control_put, | ||
1119 | .private_value = 0, | ||
1120 | }, | ||
1121 | }; | ||
988 | static const struct snd_kcontrol_new lc_controls[] = { | 1122 | static const struct snd_kcontrol_new lc_controls[] = { |
989 | WM8776_FIELD_CTL_VOLUME("Limiter Threshold", | 1123 | WM8776_FIELD_CTL_VOLUME("Limiter Threshold", |
990 | WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, | 1124 | WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, |
@@ -1028,6 +1162,26 @@ static const struct snd_kcontrol_new lc_controls[] = { | |||
1028 | LC_CONTROL_ALC, wm8776_ngth_db_scale), | 1162 | LC_CONTROL_ALC, wm8776_ngth_db_scale), |
1029 | }; | 1163 | }; |
1030 | 1164 | ||
1165 | static int add_lc_controls(struct oxygen *chip) | ||
1166 | { | ||
1167 | struct xonar_wm87x6 *data = chip->model_data; | ||
1168 | unsigned int i; | ||
1169 | struct snd_kcontrol *ctl; | ||
1170 | int err; | ||
1171 | |||
1172 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); | ||
1173 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { | ||
1174 | ctl = snd_ctl_new1(&lc_controls[i], chip); | ||
1175 | if (!ctl) | ||
1176 | return -ENOMEM; | ||
1177 | err = snd_ctl_add(chip->card, ctl); | ||
1178 | if (err < 0) | ||
1179 | return err; | ||
1180 | data->lc_controls[i] = ctl; | ||
1181 | } | ||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1031 | static int xonar_ds_mixer_init(struct oxygen *chip) | 1185 | static int xonar_ds_mixer_init(struct oxygen *chip) |
1032 | { | 1186 | { |
1033 | struct xonar_wm87x6 *data = chip->model_data; | 1187 | struct xonar_wm87x6 *data = chip->model_data; |
@@ -1049,17 +1203,54 @@ static int xonar_ds_mixer_init(struct oxygen *chip) | |||
1049 | } | 1203 | } |
1050 | if (!data->line_adcmux_control || !data->mic_adcmux_control) | 1204 | if (!data->line_adcmux_control || !data->mic_adcmux_control) |
1051 | return -ENXIO; | 1205 | return -ENXIO; |
1052 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); | 1206 | |
1053 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { | 1207 | return add_lc_controls(chip); |
1054 | ctl = snd_ctl_new1(&lc_controls[i], chip); | 1208 | } |
1209 | |||
1210 | static int xonar_hdav_slim_mixer_init(struct oxygen *chip) | ||
1211 | { | ||
1212 | unsigned int i; | ||
1213 | struct snd_kcontrol *ctl; | ||
1214 | int err; | ||
1215 | |||
1216 | for (i = 0; i < ARRAY_SIZE(hdav_slim_controls); ++i) { | ||
1217 | ctl = snd_ctl_new1(&hdav_slim_controls[i], chip); | ||
1055 | if (!ctl) | 1218 | if (!ctl) |
1056 | return -ENOMEM; | 1219 | return -ENOMEM; |
1057 | err = snd_ctl_add(chip->card, ctl); | 1220 | err = snd_ctl_add(chip->card, ctl); |
1058 | if (err < 0) | 1221 | if (err < 0) |
1059 | return err; | 1222 | return err; |
1060 | data->lc_controls[i] = ctl; | ||
1061 | } | 1223 | } |
1062 | return 0; | 1224 | |
1225 | return add_lc_controls(chip); | ||
1226 | } | ||
1227 | |||
1228 | static void dump_wm8776_registers(struct oxygen *chip, | ||
1229 | struct snd_info_buffer *buffer) | ||
1230 | { | ||
1231 | struct xonar_wm87x6 *data = chip->model_data; | ||
1232 | unsigned int i; | ||
1233 | |||
1234 | snd_iprintf(buffer, "\nWM8776:\n00:"); | ||
1235 | for (i = 0; i < 0x10; ++i) | ||
1236 | snd_iprintf(buffer, " %03x", data->wm8776_regs[i]); | ||
1237 | snd_iprintf(buffer, "\n10:"); | ||
1238 | for (i = 0x10; i < 0x17; ++i) | ||
1239 | snd_iprintf(buffer, " %03x", data->wm8776_regs[i]); | ||
1240 | snd_iprintf(buffer, "\n"); | ||
1241 | } | ||
1242 | |||
1243 | static void dump_wm87x6_registers(struct oxygen *chip, | ||
1244 | struct snd_info_buffer *buffer) | ||
1245 | { | ||
1246 | struct xonar_wm87x6 *data = chip->model_data; | ||
1247 | unsigned int i; | ||
1248 | |||
1249 | dump_wm8776_registers(chip, buffer); | ||
1250 | snd_iprintf(buffer, "\nWM8766:\n00:"); | ||
1251 | for (i = 0; i < 0x10; ++i) | ||
1252 | snd_iprintf(buffer, " %03x", data->wm8766_regs[i]); | ||
1253 | snd_iprintf(buffer, "\n"); | ||
1063 | } | 1254 | } |
1064 | 1255 | ||
1065 | static const struct oxygen_model model_xonar_ds = { | 1256 | static const struct oxygen_model model_xonar_ds = { |
@@ -1072,22 +1263,57 @@ static const struct oxygen_model model_xonar_ds = { | |||
1072 | .suspend = xonar_ds_suspend, | 1263 | .suspend = xonar_ds_suspend, |
1073 | .resume = xonar_ds_resume, | 1264 | .resume = xonar_ds_resume, |
1074 | .pcm_hardware_filter = wm8776_adc_hardware_filter, | 1265 | .pcm_hardware_filter = wm8776_adc_hardware_filter, |
1075 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
1076 | .set_dac_params = set_wm87x6_dac_params, | 1266 | .set_dac_params = set_wm87x6_dac_params, |
1077 | .set_adc_params = set_wm8776_adc_params, | 1267 | .set_adc_params = set_wm8776_adc_params, |
1078 | .update_dac_volume = update_wm87x6_volume, | 1268 | .update_dac_volume = update_wm87x6_volume, |
1079 | .update_dac_mute = update_wm87x6_mute, | 1269 | .update_dac_mute = update_wm87x6_mute, |
1080 | .update_center_lfe_mix = update_wm8766_center_lfe_mix, | 1270 | .update_center_lfe_mix = update_wm8766_center_lfe_mix, |
1081 | .gpio_changed = xonar_ds_gpio_changed, | 1271 | .gpio_changed = xonar_ds_gpio_changed, |
1272 | .dump_registers = dump_wm87x6_registers, | ||
1082 | .dac_tlv = wm87x6_dac_db_scale, | 1273 | .dac_tlv = wm87x6_dac_db_scale, |
1083 | .model_data_size = sizeof(struct xonar_wm87x6), | 1274 | .model_data_size = sizeof(struct xonar_wm87x6), |
1084 | .device_config = PLAYBACK_0_TO_I2S | | 1275 | .device_config = PLAYBACK_0_TO_I2S | |
1085 | PLAYBACK_1_TO_SPDIF | | 1276 | PLAYBACK_1_TO_SPDIF | |
1086 | CAPTURE_0_FROM_I2S_1, | 1277 | CAPTURE_0_FROM_I2S_1, |
1087 | .dac_channels = 8, | 1278 | .dac_channels_pcm = 8, |
1279 | .dac_channels_mixer = 8, | ||
1088 | .dac_volume_min = 255 - 2*60, | 1280 | .dac_volume_min = 255 - 2*60, |
1089 | .dac_volume_max = 255, | 1281 | .dac_volume_max = 255, |
1090 | .function_flags = OXYGEN_FUNCTION_SPI, | 1282 | .function_flags = OXYGEN_FUNCTION_SPI, |
1283 | .dac_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1284 | .adc_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1285 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1286 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
1287 | }; | ||
1288 | |||
1289 | static const struct oxygen_model model_xonar_hdav_slim = { | ||
1290 | .shortname = "Xonar HDAV1.3 Slim", | ||
1291 | .longname = "Asus Virtuoso 200", | ||
1292 | .chip = "AV200", | ||
1293 | .init = xonar_hdav_slim_init, | ||
1294 | .mixer_init = xonar_hdav_slim_mixer_init, | ||
1295 | .cleanup = xonar_hdav_slim_cleanup, | ||
1296 | .suspend = xonar_hdav_slim_suspend, | ||
1297 | .resume = xonar_hdav_slim_resume, | ||
1298 | .pcm_hardware_filter = xonar_hdav_slim_hardware_filter, | ||
1299 | .set_dac_params = set_hdav_slim_dac_params, | ||
1300 | .set_adc_params = set_wm8776_adc_params, | ||
1301 | .update_dac_volume = update_wm8776_volume, | ||
1302 | .update_dac_mute = update_wm8776_mute, | ||
1303 | .uart_input = xonar_hdmi_uart_input, | ||
1304 | .dump_registers = dump_wm8776_registers, | ||
1305 | .dac_tlv = wm87x6_dac_db_scale, | ||
1306 | .model_data_size = sizeof(struct xonar_wm87x6), | ||
1307 | .device_config = PLAYBACK_0_TO_I2S | | ||
1308 | PLAYBACK_1_TO_SPDIF | | ||
1309 | CAPTURE_0_FROM_I2S_1, | ||
1310 | .dac_channels_pcm = 8, | ||
1311 | .dac_channels_mixer = 2, | ||
1312 | .dac_volume_min = 255 - 2*60, | ||
1313 | .dac_volume_max = 255, | ||
1314 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
1315 | .dac_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1316 | .adc_mclks = OXYGEN_MCLKS(256, 256, 128), | ||
1091 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1317 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1092 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1318 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
1093 | }; | 1319 | }; |
@@ -1099,6 +1325,9 @@ int __devinit get_xonar_wm87x6_model(struct oxygen *chip, | |||
1099 | case 0x838e: | 1325 | case 0x838e: |
1100 | chip->model = model_xonar_ds; | 1326 | chip->model = model_xonar_ds; |
1101 | break; | 1327 | break; |
1328 | case 0x835e: | ||
1329 | chip->model = model_xonar_hdav_slim; | ||
1330 | break; | ||
1102 | default: | 1331 | default: |
1103 | return -EINVAL; | 1332 | return -EINVAL; |
1104 | } | 1333 | } |