62 #include <linux/pci.h>
75 #define GPIO_DS_HP_DETECT 0x0010
76 #define GPIO_DS_INPUT_ROUTE 0x0040
77 #define GPIO_DS_OUTPUT_FRONTLR 0x0080
78 #define GPIO_DS_OUTPUT_ENABLE 0x0100
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
85 #define I2C_DEVICE_WM8776 0x34
87 #define LC_CONTROL_LIMITER 0x40000000
88 #define LC_CONTROL_ALC 0x20000000
101 static void wm8776_write_spi(
struct oxygen *
chip,
102 unsigned int reg,
unsigned int value)
112 static void wm8776_write_i2c(
struct oxygen *chip,
113 unsigned int reg,
unsigned int value)
116 (reg << 1) | (value >> 8), value);
119 static void wm8776_write(
struct oxygen *chip,
120 unsigned int reg,
unsigned int value)
126 wm8776_write_spi(chip, reg, value);
128 wm8776_write_i2c(chip, reg, value);
136 static void wm8776_write_cached(
struct oxygen *chip,
137 unsigned int reg,
unsigned int value)
143 wm8776_write(chip, reg, value);
146 static void wm8766_write(
struct oxygen *chip,
147 unsigned int reg,
unsigned int value)
165 static void wm8766_write_cached(
struct oxygen *chip,
166 unsigned int reg,
unsigned int value)
172 wm8766_write(chip, reg, value);
175 static void wm8776_registers_init(
struct oxygen *chip)
200 static void wm8766_registers_init(
struct oxygen *chip)
217 static void wm8776_init(
struct oxygen *chip)
231 wm8776_registers_init(chip);
234 static void wm8766_init(
struct oxygen *chip)
240 wm8766_registers_init(chip);
243 static void xonar_ds_handle_hp_jack(
struct oxygen *chip)
256 GPIO_DS_OUTPUT_FRONTLR);
268 static void xonar_ds_init(
struct oxygen *chip)
272 data->
generic.anti_pop_delay = 300;
290 xonar_ds_handle_hp_jack(chip);
296 static void xonar_hdav_slim_init(
struct oxygen *chip)
300 data->
generic.anti_pop_delay = 300;
316 static void xonar_ds_cleanup(
struct oxygen *chip)
322 static void xonar_hdav_slim_cleanup(
struct oxygen *chip)
330 static void xonar_ds_suspend(
struct oxygen *chip)
332 xonar_ds_cleanup(chip);
335 static void xonar_hdav_slim_suspend(
struct oxygen *chip)
337 xonar_hdav_slim_cleanup(chip);
340 static void xonar_ds_resume(
struct oxygen *chip)
342 wm8776_registers_init(chip);
343 wm8766_registers_init(chip);
345 xonar_ds_handle_hp_jack(chip);
348 static void xonar_hdav_slim_resume(
struct oxygen *chip)
352 wm8776_registers_init(chip);
357 static void wm8776_adc_hardware_filter(
unsigned int channel,
360 if (channel ==
PCM_A) {
371 static void xonar_hdav_slim_hardware_filter(
unsigned int channel,
374 wm8776_adc_hardware_filter(channel, hardware);
378 static void set_wm87x6_dac_params(
struct oxygen *chip,
383 static void set_wm8776_adc_params(
struct oxygen *chip,
394 static void set_hdav_slim_dac_params(
struct oxygen *chip,
402 static void update_wm8776_volume(
struct oxygen *chip)
429 static void update_wm87x6_volume(
struct oxygen *chip)
440 update_wm8776_volume(chip);
447 for (i = 0; i < 6; ++
i)
454 for (i = 0; i < 6; ++
i)
460 for (i = 0; i < 6; ++
i)
463 for (i = 0; i < 6; ++
i)
464 if (to_change & (1 << i))
465 wm8766_write(chip, wm8766_regs[i],
467 ((to_change & (0x3e << i))
472 static void update_wm8776_mute(
struct oxygen *chip)
478 static void update_wm87x6_mute(
struct oxygen *chip)
480 update_wm8776_mute(chip);
485 static void update_wm8766_center_lfe_mix(
struct oxygen *chip,
bool mixed)
503 static void xonar_ds_gpio_changed(
struct oxygen *chip)
505 xonar_ds_handle_hp_jack(chip);
517 value->
value.integer.value[0] =
535 if (value->
value.integer.value[0] ^ invert)
537 changed = reg_value != data->
wm8776_regs[reg_index];
539 wm8776_write(chip, reg_index, reg_value);
544 static int wm8776_field_enum_info(
struct snd_kcontrol *ctl,
547 static const char *
const hld[16] = {
548 "0 ms",
"2.67 ms",
"5.33 ms",
"10.6 ms",
549 "21.3 ms",
"42.7 ms",
"85.3 ms",
"171 ms",
550 "341 ms",
"683 ms",
"1.37 s",
"2.73 s",
551 "5.46 s",
"10.9 s",
"21.8 s",
"43.7 s",
553 static const char *
const atk_lim[11] = {
554 "0.25 ms",
"0.5 ms",
"1 ms",
"2 ms",
555 "4 ms",
"8 ms",
"16 ms",
"32 ms",
556 "64 ms",
"128 ms",
"256 ms",
558 static const char *
const atk_alc[11] = {
559 "8.40 ms",
"16.8 ms",
"33.6 ms",
"67.2 ms",
560 "134 ms",
"269 ms",
"538 ms",
"1.08 s",
561 "2.15 s",
"4.3 s",
"8.6 s",
563 static const char *
const dcy_lim[11] = {
564 "1.2 ms",
"2.4 ms",
"4.8 ms",
"9.6 ms",
565 "19.2 ms",
"38.4 ms",
"76.8 ms",
"154 ms",
566 "307 ms",
"614 ms",
"1.23 s",
568 static const char *
const dcy_alc[11] = {
569 "33.5 ms",
"67.0 ms",
"134 ms",
"268 ms",
570 "536 ms",
"1.07 s",
"2.14 s",
"4.29 s",
571 "8.58 s",
"17.2 s",
"34.3 s",
573 static const char *
const tranwin[8] = {
574 "0 us",
"62.5 us",
"125 us",
"250 us",
575 "500 us",
"1 ms",
"2 ms",
"4 ms",
578 const char *
const *names;
607 static int wm8776_field_volume_info(
struct snd_kcontrol *ctl,
617 static void wm8776_field_set_from_ctl(
struct snd_kcontrol *ctl)
643 value = max - (value -
min);
645 reg_value &= ~(mask << shift);
646 reg_value |= value << shift;
647 wm8776_write_cached(chip, reg_index, reg_value);
650 static int wm8776_field_set(
struct snd_kcontrol *ctl,
unsigned int value)
658 if (value < min || value > max)
664 wm8776_field_set_from_ctl(ctl);
670 static int wm8776_field_enum_get(
struct snd_kcontrol *ctl,
677 static int wm8776_field_volume_get(
struct snd_kcontrol *ctl,
684 static int wm8776_field_enum_put(
struct snd_kcontrol *ctl,
687 return wm8776_field_set(ctl, value->
value.enumerated.item[0]);
690 static int wm8776_field_volume_put(
struct snd_kcontrol *ctl,
693 return wm8776_field_set(ctl, value->
value.integer.value[0]);
713 value->
value.integer.value[0] =
715 value->
value.integer.value[1] =
729 to_update = (value->
value.integer.value[0] !=
732 to_update |= (value->
value.integer.value[1] !=
735 if (value->
value.integer.value[0] == value->
value.integer.value[1]) {
738 value->
value.integer.value[0] |
748 value->
value.integer.value[0] |
753 value->
value.integer.value[1] |
757 return to_update != 0;
760 static int wm8776_input_mux_get(
struct snd_kcontrol *ctl,
767 value->
value.integer.value[0] =
772 static int wm8776_input_mux_put(
struct snd_kcontrol *ctl,
784 if (value->
value.integer.value[0]) {
803 GPIO_DS_INPUT_ROUTE);
810 static int wm8776_input_vol_info(
struct snd_kcontrol *ctl,
820 static int wm8776_input_vol_get(
struct snd_kcontrol *ctl,
827 value->
value.integer.value[0] =
829 value->
value.integer.value[1] =
835 static int wm8776_input_vol_put(
struct snd_kcontrol *ctl,
843 changed = (value->
value.integer.value[0] !=
845 (value->
value.integer.value[1] !=
855 static int wm8776_level_control_info(
struct snd_kcontrol *ctl,
858 static const char *
const names[3] = {
859 "None",
"Peak Limiter",
"Automatic Level Control"
865 static int wm8776_level_control_get(
struct snd_kcontrol *ctl,
872 value->
value.enumerated.item[0] = 0;
875 value->
value.enumerated.item[0] = 1;
877 value->
value.enumerated.item[0] = 2;
881 static void activate_control(
struct oxygen *chip,
896 static int wm8776_level_control_put(
struct snd_kcontrol *ctl,
901 unsigned int mode = 0,
i;
905 if (value->
value.enumerated.item[0] >= 3)
913 switch (value->
value.enumerated.item[0]) {
916 ctrl2 & ~WM8776_LCEN);
920 (ctrl1 & ~WM8776_LCSEL_MASK) |
923 ctrl2 | WM8776_LCEN);
928 (ctrl1 & ~WM8776_LCSEL_MASK) |
931 ctrl2 | WM8776_LCEN);
936 activate_control(chip, data->
lc_controls[i], mode);
944 static const char *
const names[2] = {
945 "None",
"High-pass Filter"
956 value->
value.enumerated.item[0] =
970 if (!value->
value.enumerated.item[0])
979 #define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \
980 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
982 .info = snd_ctl_boolean_mono_info, \
983 .get = wm8776_bit_switch_get, \
984 .put = wm8776_bit_switch_put, \
985 .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \
987 #define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \
988 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
990 .private_value = (initval) | ((min) << 8) | ((max) << 12) | \
991 ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags)
992 #define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\
993 _WM8776_FIELD_CTL(xname " Capture Enum", \
994 reg, shift, init, min, max, mask, flags), \
995 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
996 SNDRV_CTL_ELEM_ACCESS_INACTIVE, \
997 .info = wm8776_field_enum_info, \
998 .get = wm8776_field_enum_get, \
999 .put = wm8776_field_enum_put, \
1001 #define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \
1002 _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \
1003 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1004 SNDRV_CTL_ELEM_ACCESS_INACTIVE | \
1005 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
1006 .info = wm8776_field_volume_info, \
1007 .get = wm8776_field_volume_get, \
1008 .put = wm8776_field_volume_put, \
1009 .tlv = { .p = tlv_p }, \
1024 .name =
"Headphone Playback Volume",
1025 .info = wm8776_hp_vol_info,
1026 .get = wm8776_hp_vol_get,
1027 .put = wm8776_hp_vol_put,
1028 .tlv = { .p = wm8776_hp_db_scale },
1034 .name =
"Input Capture Volume",
1035 .info = wm8776_input_vol_info,
1036 .get = wm8776_input_vol_get,
1037 .put = wm8776_input_vol_put,
1038 .tlv = { .p = wm8776_adc_db_scale },
1042 .name =
"Line Capture Switch",
1044 .get = wm8776_input_mux_get,
1045 .put = wm8776_input_mux_put,
1046 .private_value = 1 << 0,
1050 .name =
"Mic Capture Switch",
1052 .get = wm8776_input_mux_get,
1053 .put = wm8776_input_mux_put,
1054 .private_value = 1 << 1,
1062 .name =
"ADC Filter Capture Enum",
1069 .name =
"Level Control Capture Enum",
1070 .info = wm8776_level_control_info,
1071 .get = wm8776_level_control_get,
1072 .put = wm8776_level_control_put,
1079 .name =
"HDMI Playback Switch",
1087 .name =
"Headphone Playback Volume",
1088 .info = wm8776_hp_vol_info,
1089 .get = wm8776_hp_vol_get,
1090 .put = wm8776_hp_vol_put,
1091 .tlv = { .p = wm8776_hp_db_scale },
1097 .name =
"Input Capture Volume",
1098 .info = wm8776_input_vol_info,
1099 .get = wm8776_input_vol_get,
1100 .put = wm8776_input_vol_put,
1101 .tlv = { .p = wm8776_adc_db_scale },
1109 .name =
"ADC Filter Capture Enum",
1116 .name =
"Level Control Capture Enum",
1117 .info = wm8776_level_control_info,
1118 .get = wm8776_level_control_get,
1119 .put = wm8776_level_control_put,
1139 wm8776_maxatten_lim_db_scale),
1166 static int add_lc_controls(
struct oxygen *chip)
1186 static int xonar_ds_mixer_init(
struct oxygen *chip)
1200 if (!
strcmp(ctl->
id.name,
"Line Capture Switch"))
1202 else if (!
strcmp(ctl->
id.name,
"Mic Capture Switch"))
1208 return add_lc_controls(chip);
1211 static int xonar_hdav_slim_mixer_init(
struct oxygen *chip)
1217 for (i = 0; i <
ARRAY_SIZE(hdav_slim_controls); ++
i) {
1226 return add_lc_controls(chip);
1229 static void dump_wm8776_registers(
struct oxygen *chip,
1235 snd_iprintf(buffer,
"\nWM8776:\n00:");
1236 for (i = 0; i < 0x10; ++
i)
1237 snd_iprintf(buffer,
" %03x", data->
wm8776_regs[i]);
1238 snd_iprintf(buffer,
"\n10:");
1239 for (i = 0x10; i < 0x17; ++
i)
1240 snd_iprintf(buffer,
" %03x", data->
wm8776_regs[i]);
1241 snd_iprintf(buffer,
"\n");
1244 static void dump_wm87x6_registers(
struct oxygen *chip,
1250 dump_wm8776_registers(chip, buffer);
1251 snd_iprintf(buffer,
"\nWM8766:\n00:");
1252 for (i = 0; i < 0x10; ++
i)
1253 snd_iprintf(buffer,
" %03x", data->
wm8766_regs[i]);
1254 snd_iprintf(buffer,
"\n");
1258 .shortname =
"Xonar DS",
1259 .longname =
"Asus Virtuoso 66",
1261 .init = xonar_ds_init,
1262 .mixer_init = xonar_ds_mixer_init,
1263 .cleanup = xonar_ds_cleanup,
1264 .suspend = xonar_ds_suspend,
1265 .resume = xonar_ds_resume,
1266 .pcm_hardware_filter = wm8776_adc_hardware_filter,
1267 .set_dac_params = set_wm87x6_dac_params,
1268 .set_adc_params = set_wm8776_adc_params,
1269 .update_dac_volume = update_wm87x6_volume,
1270 .update_dac_mute = update_wm87x6_mute,
1271 .update_center_lfe_mix = update_wm8766_center_lfe_mix,
1272 .gpio_changed = xonar_ds_gpio_changed,
1273 .dump_registers = dump_wm87x6_registers,
1274 .dac_tlv = wm87x6_dac_db_scale,
1280 .dac_channels_pcm = 8,
1281 .dac_channels_mixer = 8,
1282 .dac_volume_min = 255 - 2*60,
1283 .dac_volume_max = 255,
1291 static const struct oxygen_model model_xonar_hdav_slim = {
1292 .shortname =
"Xonar HDAV1.3 Slim",
1293 .longname =
"Asus Virtuoso 200",
1295 .init = xonar_hdav_slim_init,
1296 .mixer_init = xonar_hdav_slim_mixer_init,
1297 .cleanup = xonar_hdav_slim_cleanup,
1298 .suspend = xonar_hdav_slim_suspend,
1299 .resume = xonar_hdav_slim_resume,
1300 .pcm_hardware_filter = xonar_hdav_slim_hardware_filter,
1301 .set_dac_params = set_hdav_slim_dac_params,
1302 .set_adc_params = set_wm8776_adc_params,
1303 .update_dac_volume = update_wm8776_volume,
1304 .update_dac_mute = update_wm8776_mute,
1306 .dump_registers = dump_wm8776_registers,
1307 .dac_tlv = wm87x6_dac_db_scale,
1313 .dac_channels_pcm = 8,
1314 .dac_channels_mixer = 2,
1315 .dac_volume_min = 255 - 2*60,
1316 .dac_volume_max = 255,
1329 chip->
model = model_xonar_ds;
1332 chip->
model = model_xonar_hdav_slim;