aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/oxygen
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/oxygen')
-rw-r--r--sound/pci/oxygen/oxygen.c4
-rw-r--r--sound/pci/oxygen/oxygen.h1
-rw-r--r--sound/pci/oxygen/oxygen_lib.c55
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c5
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c12
-rw-r--r--sound/pci/oxygen/oxygen_regs.h10
-rw-r--r--sound/pci/oxygen/virtuoso.c5
-rw-r--r--sound/pci/oxygen/xonar_cs43xx.c8
-rw-r--r--sound/pci/oxygen/xonar_pcm179x.c29
-rw-r--r--sound/pci/oxygen/xonar_wm87x6.c121
10 files changed, 173 insertions, 77 deletions
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 6c0a11adb2a8..98a8eb3c92f7 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -79,6 +79,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
79 { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, 79 { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
80 { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF }, 80 { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
81 { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, 81 { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
82 { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF },
82 { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, 83 { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
83 { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, 84 { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
84 { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, 85 { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
@@ -505,7 +506,8 @@ static const struct oxygen_model model_generic = {
505 PLAYBACK_2_TO_AC97_1 | 506 PLAYBACK_2_TO_AC97_1 |
506 CAPTURE_0_FROM_I2S_1 | 507 CAPTURE_0_FROM_I2S_1 |
507 CAPTURE_1_FROM_SPDIF | 508 CAPTURE_1_FROM_SPDIF |
508 CAPTURE_2_FROM_AC97_1, 509 CAPTURE_2_FROM_AC97_1 |
510 AC97_CD_INPUT,
509 .dac_channels = 8, 511 .dac_channels = 8,
510 .dac_volume_min = 0, 512 .dac_volume_min = 0,
511 .dac_volume_max = 255, 513 .dac_volume_max = 255,
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index a3409edcfb50..7d5222caa0a9 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -34,6 +34,7 @@
34 /* CAPTURE_3_FROM_I2S_3 not implemented */ 34 /* CAPTURE_3_FROM_I2S_3 not implemented */
35#define MIDI_OUTPUT 0x0800 35#define MIDI_OUTPUT 0x0800
36#define MIDI_INPUT 0x1000 36#define MIDI_INPUT 0x1000
37#define AC97_CD_INPUT 0x2000
37 38
38enum { 39enum {
39 CONTROL_SPDIF_PCM, 40 CONTROL_SPDIF_PCM,
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 7e93cf884437..e5ebe56fb0c5 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -308,25 +308,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
308 } 308 }
309} 309}
310 310
311static void pci_bridge_magic(void) 311static void configure_pcie_bridge(struct pci_dev *pci)
312{ 312{
313 struct pci_dev *pci = NULL; 313 enum { PEX811X, PI7C9X110 };
314 static const struct pci_device_id bridge_ids[] = {
315 { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
316 { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
317 { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
318 { }
319 };
320 struct pci_dev *bridge;
321 const struct pci_device_id *id;
314 u32 tmp; 322 u32 tmp;
315 323
316 for (;;) { 324 if (!pci->bus || !pci->bus->self)
317 /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */ 325 return;
318 pci = pci_get_device(0x12d8, 0xe110, pci); 326 bridge = pci->bus->self;
319 if (!pci) 327
320 break; 328 id = pci_match_id(bridge_ids, bridge);
321 /* 329 if (!id)
322 * ... configure its secondary internal arbiter to park to 330 return;
323 * the secondary port, instead of to the last master. 331
324 */ 332 switch (id->driver_data) {
325 if (!pci_read_config_dword(pci, 0x40, &tmp)) { 333 case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */
326 tmp |= 1; 334 pci_read_config_dword(bridge, 0x48, &tmp);
327 pci_write_config_dword(pci, 0x40, tmp); 335 tmp |= 1; /* enable blind prefetching */
328 } 336 tmp |= 1 << 11; /* enable beacon generation */
329 /* Why? Try asking C-Media. */ 337 pci_write_config_dword(bridge, 0x48, tmp);
338
339 pci_write_config_dword(bridge, 0x84, 0x0c);
340 pci_read_config_dword(bridge, 0x88, &tmp);
341 tmp &= ~(7 << 27);
342 tmp |= 2 << 27; /* set prefetch size to 128 bytes */
343 pci_write_config_dword(bridge, 0x88, tmp);
344 break;
345
346 case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */
347 pci_read_config_dword(bridge, 0x40, &tmp);
348 tmp |= 1; /* park the PCI arbiter to the sound chip */
349 pci_write_config_dword(bridge, 0x40, tmp);
350 break;
330 } 351 }
331} 352}
332 353
@@ -613,7 +634,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
613 snd_card_set_dev(card, &pci->dev); 634 snd_card_set_dev(card, &pci->dev);
614 card->private_free = oxygen_card_free; 635 card->private_free = oxygen_card_free;
615 636
616 pci_bridge_magic(); 637 configure_pcie_bridge(pci);
617 oxygen_init(chip); 638 oxygen_init(chip);
618 chip->model.init(chip); 639 chip->model.init(chip);
619 640
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index f375b8a27862..2849b36f5f7e 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -708,7 +708,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
708 .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \ 708 .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
709 } 709 }
710 710
711static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0); 711static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0);
712static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); 712static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
713static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); 713static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
714 714
@@ -972,6 +972,9 @@ static int add_controls(struct oxygen *chip,
972 if (!strcmp(template.name, "Stereo Upmixing") && 972 if (!strcmp(template.name, "Stereo Upmixing") &&
973 chip->model.dac_channels == 2) 973 chip->model.dac_channels == 2)
974 continue; 974 continue;
975 if (!strncmp(template.name, "CD Capture ", 11) &&
976 !(chip->model.device_config & AC97_CD_INPUT))
977 continue;
975 if (!strcmp(template.name, "Master Playback Volume") && 978 if (!strcmp(template.name, "Master Playback Volume") &&
976 chip->model.dac_tlv) { 979 chip->model.dac_tlv) {
977 template.tlv.p = chip->model.dac_tlv; 980 template.tlv.p = chip->model.dac_tlv;
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index 9dff6954c397..814667442eb0 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -56,8 +56,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
56 .channels_max = 2, 56 .channels_max = 2,
57 .buffer_bytes_max = BUFFER_BYTES_MAX, 57 .buffer_bytes_max = BUFFER_BYTES_MAX,
58 .period_bytes_min = PERIOD_BYTES_MIN, 58 .period_bytes_min = PERIOD_BYTES_MIN,
59 .period_bytes_max = BUFFER_BYTES_MAX / 2, 59 .period_bytes_max = BUFFER_BYTES_MAX,
60 .periods_min = 2, 60 .periods_min = 1,
61 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, 61 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
62}; 62};
63static const struct snd_pcm_hardware oxygen_multichannel_hardware = { 63static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
@@ -82,8 +82,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
82 .channels_max = 8, 82 .channels_max = 8,
83 .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, 83 .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH,
84 .period_bytes_min = PERIOD_BYTES_MIN, 84 .period_bytes_min = PERIOD_BYTES_MIN,
85 .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2, 85 .period_bytes_max = BUFFER_BYTES_MAX_MULTICH,
86 .periods_min = 2, 86 .periods_min = 1,
87 .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, 87 .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
88}; 88};
89static const struct snd_pcm_hardware oxygen_ac97_hardware = { 89static const struct snd_pcm_hardware oxygen_ac97_hardware = {
@@ -100,8 +100,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
100 .channels_max = 2, 100 .channels_max = 2,
101 .buffer_bytes_max = BUFFER_BYTES_MAX, 101 .buffer_bytes_max = BUFFER_BYTES_MAX,
102 .period_bytes_min = PERIOD_BYTES_MIN, 102 .period_bytes_min = PERIOD_BYTES_MIN,
103 .period_bytes_max = BUFFER_BYTES_MAX / 2, 103 .period_bytes_max = BUFFER_BYTES_MAX,
104 .periods_min = 2, 104 .periods_min = 1,
105 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, 105 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
106}; 106};
107 107
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h
index 72de159d4567..4dcd41b78258 100644
--- a/sound/pci/oxygen/oxygen_regs.h
+++ b/sound/pci/oxygen/oxygen_regs.h
@@ -436,13 +436,15 @@
436/* OXYGEN_CHANNEL_* */ 436/* OXYGEN_CHANNEL_* */
437 437
438#define OXYGEN_CODEC_VERSION 0xe4 438#define OXYGEN_CODEC_VERSION 0xe4
439#define OXYGEN_XCID_MASK 0x07 439#define OXYGEN_CODEC_ID_MASK 0x07
440 440
441#define OXYGEN_REVISION 0xe6 441#define OXYGEN_REVISION 0xe6
442#define OXYGEN_REVISION_XPKGID_MASK 0x0007 442#define OXYGEN_PACKAGE_ID_MASK 0x0007
443#define OXYGEN_PACKAGE_ID_8786 0x0004
444#define OXYGEN_PACKAGE_ID_8787 0x0006
445#define OXYGEN_PACKAGE_ID_8788 0x0007
443#define OXYGEN_REVISION_MASK 0xfff8 446#define OXYGEN_REVISION_MASK 0xfff8
444#define OXYGEN_REVISION_2 0x0008 /* bit flag */ 447#define OXYGEN_REVISION_2 0x0008
445#define OXYGEN_REVISION_8787 0x0014 /* 8 bits */
446 448
447#define OXYGEN_OFFSIN_48K 0xe8 449#define OXYGEN_OFFSIN_48K 0xe8
448#define OXYGEN_OFFSBASE_48K 0xe9 450#define OXYGEN_OFFSBASE_48K 0xe9
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 06c863e86e3d..469010a8b849 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -25,9 +25,9 @@
25#include "xonar.h" 25#include "xonar.h"
26 26
27MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); 27MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
28MODULE_DESCRIPTION("Asus AVx00 driver"); 28MODULE_DESCRIPTION("Asus Virtuoso driver");
29MODULE_LICENSE("GPL v2"); 29MODULE_LICENSE("GPL v2");
30MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); 30MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}");
31 31
32static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 32static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
33static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 33static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = {
49 { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, 49 { OXYGEN_PCI_SUBID(0x1043, 0x834f) },
50 { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, 50 { OXYGEN_PCI_SUBID(0x1043, 0x835c) },
51 { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, 51 { OXYGEN_PCI_SUBID(0x1043, 0x835d) },
52 { OXYGEN_PCI_SUBID(0x1043, 0x835e) },
52 { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, 53 { OXYGEN_PCI_SUBID(0x1043, 0x838e) },
53 { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, 54 { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
54 { } 55 { }
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c
index 7c4986b27f2b..aa27c31049af 100644
--- a/sound/pci/oxygen/xonar_cs43xx.c
+++ b/sound/pci/oxygen/xonar_cs43xx.c
@@ -367,13 +367,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip,
367 367
368static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); 368static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
369 369
370static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
371{
372 if (!strncmp(template->name, "CD Capture ", 11))
373 return 1; /* no CD input */
374 return 0;
375}
376
377static int xonar_d1_mixer_init(struct oxygen *chip) 370static int xonar_d1_mixer_init(struct oxygen *chip)
378{ 371{
379 int err; 372 int err;
@@ -391,7 +384,6 @@ static const struct oxygen_model model_xonar_d1 = {
391 .longname = "Asus Virtuoso 100", 384 .longname = "Asus Virtuoso 100",
392 .chip = "AV200", 385 .chip = "AV200",
393 .init = xonar_d1_init, 386 .init = xonar_d1_init,
394 .control_filter = xonar_d1_control_filter,
395 .mixer_init = xonar_d1_mixer_init, 387 .mixer_init = xonar_d1_mixer_init,
396 .cleanup = xonar_d1_cleanup, 388 .cleanup = xonar_d1_cleanup,
397 .suspend = xonar_d1_suspend, 389 .suspend = xonar_d1_suspend,
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
index ba18fb546b4f..d491fd6c0be2 100644
--- a/sound/pci/oxygen/xonar_pcm179x.c
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -132,6 +132,18 @@
132 * GPIO 5 <- 0 132 * GPIO 5 <- 0
133 */ 133 */
134 134
135/*
136 * Xonar HDAV1.3 Slim
137 * ------------------
138 *
139 * CMI8788:
140 *
141 * GPIO 1 -> enable output
142 *
143 * TXD -> HDMI controller
144 * RXD <- HDMI controller
145 */
146
135#include <linux/pci.h> 147#include <linux/pci.h>
136#include <linux/delay.h> 148#include <linux/delay.h>
137#include <linux/mutex.h> 149#include <linux/mutex.h>
@@ -362,7 +374,6 @@ static void xonar_st_init_common(struct oxygen *chip)
362{ 374{
363 struct xonar_pcm179x *data = chip->model_data; 375 struct xonar_pcm179x *data = chip->model_data;
364 376
365 data->generic.anti_pop_delay = 100;
366 data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; 377 data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
367 data->dacs = chip->model.private_data ? 4 : 1; 378 data->dacs = chip->model.private_data ? 4 : 1;
368 data->hp_gain_offset = 2*-18; 379 data->hp_gain_offset = 2*-18;
@@ -408,6 +419,7 @@ static void xonar_st_init(struct oxygen *chip)
408{ 419{
409 struct xonar_pcm179x *data = chip->model_data; 420 struct xonar_pcm179x *data = chip->model_data;
410 421
422 data->generic.anti_pop_delay = 100;
411 data->has_cs2000 = 1; 423 data->has_cs2000 = 1;
412 data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; 424 data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
413 425
@@ -428,6 +440,7 @@ static void xonar_stx_init(struct oxygen *chip)
428 struct xonar_pcm179x *data = chip->model_data; 440 struct xonar_pcm179x *data = chip->model_data;
429 441
430 xonar_st_init_i2c(chip); 442 xonar_st_init_i2c(chip);
443 data->generic.anti_pop_delay = 800;
431 data->generic.ext_power_reg = OXYGEN_GPI_DATA; 444 data->generic.ext_power_reg = OXYGEN_GPI_DATA;
432 data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; 445 data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
433 data->generic.ext_power_bit = GPI_EXT_POWER; 446 data->generic.ext_power_bit = GPI_EXT_POWER;
@@ -915,13 +928,6 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
915 return 0; 928 return 0;
916} 929}
917 930
918static int xonar_st_control_filter(struct snd_kcontrol_new *template)
919{
920 if (!strncmp(template->name, "CD Capture ", 11))
921 return 1; /* no CD input */
922 return 0;
923}
924
925static int add_pcm1796_controls(struct oxygen *chip) 931static int add_pcm1796_controls(struct oxygen *chip)
926{ 932{
927 int err; 933 int err;
@@ -991,7 +997,8 @@ static const struct oxygen_model model_xonar_d2 = {
991 CAPTURE_0_FROM_I2S_2 | 997 CAPTURE_0_FROM_I2S_2 |
992 CAPTURE_1_FROM_SPDIF | 998 CAPTURE_1_FROM_SPDIF |
993 MIDI_OUTPUT | 999 MIDI_OUTPUT |
994 MIDI_INPUT, 1000 MIDI_INPUT |
1001 AC97_CD_INPUT,
995 .dac_channels = 8, 1002 .dac_channels = 8,
996 .dac_volume_min = 255 - 2*60, 1003 .dac_volume_min = 255 - 2*60,
997 .dac_volume_max = 255, 1004 .dac_volume_max = 255,
@@ -1037,7 +1044,6 @@ static const struct oxygen_model model_xonar_st = {
1037 .longname = "Asus Virtuoso 100", 1044 .longname = "Asus Virtuoso 100",
1038 .chip = "AV200", 1045 .chip = "AV200",
1039 .init = xonar_st_init, 1046 .init = xonar_st_init,
1040 .control_filter = xonar_st_control_filter,
1041 .mixer_init = xonar_st_mixer_init, 1047 .mixer_init = xonar_st_mixer_init,
1042 .cleanup = xonar_st_cleanup, 1048 .cleanup = xonar_st_cleanup,
1043 .suspend = xonar_st_suspend, 1049 .suspend = xonar_st_suspend,
@@ -1108,6 +1114,9 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
1108 chip->model.resume = xonar_stx_resume; 1114 chip->model.resume = xonar_stx_resume;
1109 chip->model.set_dac_params = set_pcm1796_params; 1115 chip->model.set_dac_params = set_pcm1796_params;
1110 break; 1116 break;
1117 case 0x835e:
1118 snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n");
1119 return -ENODEV;
1111 default: 1120 default:
1112 return -EINVAL; 1121 return -EINVAL;
1113 } 1122 }
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
index b82c1cfa96f5..200f7601276f 100644
--- a/sound/pci/oxygen/xonar_wm87x6.c
+++ b/sound/pci/oxygen/xonar_wm87x6.c
@@ -25,16 +25,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 28 * GPIO 4 <- headphone detect, 0 = plugged
29 * GPIO 6 -> route input jack to input 1/2 (1/0) 29 * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
30 * GPIO 7 -> enable output to speakers 30 * GPIO 7 -> enable output to front L/R speaker channels
31 * GPIO 8 -> enable output to speakers 31 * GPIO 8 -> enable output to other speaker channels and front panel headphone
32 *
33 * WM8766:
34 *
35 * input 1 <- line
36 * input 2 <- mic
37 * input 3 <- front mic
38 * input 4 <- aux
32 */ 39 */
33 40
34#include <linux/pci.h> 41#include <linux/pci.h>
35#include <linux/delay.h> 42#include <linux/delay.h>
36#include <sound/control.h> 43#include <sound/control.h>
37#include <sound/core.h> 44#include <sound/core.h>
45#include <sound/jack.h>
38#include <sound/pcm.h> 46#include <sound/pcm.h>
39#include <sound/pcm_params.h> 47#include <sound/pcm_params.h>
40#include <sound/tlv.h> 48#include <sound/tlv.h>
@@ -44,7 +52,8 @@
44 52
45#define GPIO_DS_HP_DETECT 0x0010 53#define GPIO_DS_HP_DETECT 0x0010
46#define GPIO_DS_INPUT_ROUTE 0x0040 54#define GPIO_DS_INPUT_ROUTE 0x0040
47#define GPIO_DS_OUTPUT_ENABLE 0x0180 55#define GPIO_DS_OUTPUT_FRONTLR 0x0080
56#define GPIO_DS_OUTPUT_ENABLE 0x0100
48 57
49#define LC_CONTROL_LIMITER 0x40000000 58#define LC_CONTROL_LIMITER 0x40000000
50#define LC_CONTROL_ALC 0x20000000 59#define LC_CONTROL_ALC 0x20000000
@@ -56,6 +65,7 @@ struct xonar_wm87x6 {
56 struct snd_kcontrol *line_adcmux_control; 65 struct snd_kcontrol *line_adcmux_control;
57 struct snd_kcontrol *mic_adcmux_control; 66 struct snd_kcontrol *mic_adcmux_control;
58 struct snd_kcontrol *lc_controls[13]; 67 struct snd_kcontrol *lc_controls[13];
68 struct snd_jack *hp_jack;
59}; 69};
60 70
61static void wm8776_write(struct oxygen *chip, 71static void wm8776_write(struct oxygen *chip,
@@ -97,8 +107,12 @@ static void wm8766_write(struct oxygen *chip,
97 (0 << OXYGEN_SPI_CODEC_SHIFT) | 107 (0 << OXYGEN_SPI_CODEC_SHIFT) |
98 OXYGEN_SPI_CEN_LATCH_CLOCK_LO, 108 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
99 (reg << 9) | value); 109 (reg << 9) | value);
100 if (reg < ARRAY_SIZE(data->wm8766_regs)) 110 if (reg < ARRAY_SIZE(data->wm8766_regs)) {
111 if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
112 (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
113 value &= ~WM8766_UPDATE;
101 data->wm8766_regs[reg] = value; 114 data->wm8766_regs[reg] = value;
115 }
102} 116}
103 117
104static void wm8766_write_cached(struct oxygen *chip, 118static void wm8766_write_cached(struct oxygen *chip,
@@ -107,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip,
107 struct xonar_wm87x6 *data = chip->model_data; 121 struct xonar_wm87x6 *data = chip->model_data;
108 122
109 if (reg >= ARRAY_SIZE(data->wm8766_regs) || 123 if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
110 value != data->wm8766_regs[reg]) { 124 value != data->wm8766_regs[reg])
111 if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
112 (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
113 value &= ~WM8766_UPDATE;
114 wm8766_write(chip, reg, value); 125 wm8766_write(chip, reg, value);
115 }
116} 126}
117 127
118static void wm8776_registers_init(struct oxygen *chip) 128static void wm8776_registers_init(struct oxygen *chip)
@@ -141,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip)
141 151
142static void wm8766_registers_init(struct oxygen *chip) 152static void wm8766_registers_init(struct oxygen *chip)
143{ 153{
154 struct xonar_wm87x6 *data = chip->model_data;
155
144 wm8766_write(chip, WM8766_RESET, 0); 156 wm8766_write(chip, WM8766_RESET, 0);
157 wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]);
145 wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); 158 wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
146 wm8766_write(chip, WM8766_DAC_CTRL2, 159 wm8766_write(chip, WM8766_DAC_CTRL2,
147 WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); 160 WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
@@ -170,6 +183,40 @@ static void wm8776_init(struct oxygen *chip)
170 wm8776_registers_init(chip); 183 wm8776_registers_init(chip);
171} 184}
172 185
186static void wm8766_init(struct oxygen *chip)
187{
188 struct xonar_wm87x6 *data = chip->model_data;
189
190 data->wm8766_regs[WM8766_DAC_CTRL] =
191 WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
192 wm8766_registers_init(chip);
193}
194
195static void xonar_ds_handle_hp_jack(struct oxygen *chip)
196{
197 struct xonar_wm87x6 *data = chip->model_data;
198 bool hp_plugged;
199 unsigned int reg;
200
201 mutex_lock(&chip->mutex);
202
203 hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
204 GPIO_DS_HP_DETECT);
205
206 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
207 hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
208 GPIO_DS_OUTPUT_FRONTLR);
209
210 reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
211 if (hp_plugged)
212 reg |= WM8766_MUTEALL;
213 wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
214
215 snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
216
217 mutex_unlock(&chip->mutex);
218}
219
173static void xonar_ds_init(struct oxygen *chip) 220static void xonar_ds_init(struct oxygen *chip)
174{ 221{
175 struct xonar_wm87x6 *data = chip->model_data; 222 struct xonar_wm87x6 *data = chip->model_data;
@@ -178,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip)
178 data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; 225 data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
179 226
180 wm8776_init(chip); 227 wm8776_init(chip);
181 wm8766_registers_init(chip); 228 wm8766_init(chip);
182 229
183 oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, 230 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
184 GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); 231 GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
232 oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
233 GPIO_DS_HP_DETECT);
185 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); 234 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
186 oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); 235 oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
187 chip->interrupt_mask |= OXYGEN_INT_GPIO; 236 chip->interrupt_mask |= OXYGEN_INT_GPIO;
188 237
189 xonar_enable_output(chip); 238 xonar_enable_output(chip);
190 239
240 snd_jack_new(chip->card, "Headphone",
241 SND_JACK_HEADPHONE, &data->hp_jack);
242 xonar_ds_handle_hp_jack(chip);
243
191 snd_component_add(chip->card, "WM8776"); 244 snd_component_add(chip->card, "WM8776");
192 snd_component_add(chip->card, "WM8766"); 245 snd_component_add(chip->card, "WM8766");
193} 246}
@@ -208,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip)
208 wm8776_registers_init(chip); 261 wm8776_registers_init(chip);
209 wm8766_registers_init(chip); 262 wm8766_registers_init(chip);
210 xonar_enable_output(chip); 263 xonar_enable_output(chip);
264 xonar_ds_handle_hp_jack(chip);
211} 265}
212 266
213static void wm8776_adc_hardware_filter(unsigned int channel, 267static void wm8776_adc_hardware_filter(unsigned int channel,
@@ -323,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip)
323 (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); 377 (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
324} 378}
325 379
326static void xonar_ds_gpio_changed(struct oxygen *chip) 380static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
327{ 381{
328 u16 bits; 382 struct xonar_wm87x6 *data = chip->model_data;
383 unsigned int reg;
329 384
330 bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); 385 /*
331 snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); 386 * The WM8766 can mix left and right channels, but this setting
387 * applies to all three stereo pairs.
388 */
389 reg = data->wm8766_regs[WM8766_DAC_CTRL] &
390 ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
391 if (mixed)
392 reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
393 else
394 reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
395 wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
396}
397
398static void xonar_ds_gpio_changed(struct oxygen *chip)
399{
400 xonar_ds_handle_hp_jack(chip);
332} 401}
333 402
334static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, 403static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
@@ -896,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = {
896 .put = wm8776_input_mux_put, 965 .put = wm8776_input_mux_put,
897 .private_value = 1 << 1, 966 .private_value = 1 << 1,
898 }, 967 },
899 WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), 968 WM8776_BIT_SWITCH("Front Mic Capture Switch",
969 WM8776_ADCMUX, 1 << 2, 0, 0),
970 WM8776_BIT_SWITCH("Aux Capture Switch",
971 WM8776_ADCMUX, 1 << 3, 0, 0),
900 { 972 {
901 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 973 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
902 .name = "ADC Filter Capture Enum", 974 .name = "ADC Filter Capture Enum",
@@ -956,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = {
956 LC_CONTROL_ALC, wm8776_ngth_db_scale), 1028 LC_CONTROL_ALC, wm8776_ngth_db_scale),
957}; 1029};
958 1030
959static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
960{
961 if (!strncmp(template->name, "CD Capture ", 11))
962 return 1; /* no CD input */
963 return 0;
964}
965
966static int xonar_ds_mixer_init(struct oxygen *chip) 1031static int xonar_ds_mixer_init(struct oxygen *chip)
967{ 1032{
968 struct xonar_wm87x6 *data = chip->model_data; 1033 struct xonar_wm87x6 *data = chip->model_data;
@@ -999,10 +1064,9 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
999 1064
1000static const struct oxygen_model model_xonar_ds = { 1065static const struct oxygen_model model_xonar_ds = {
1001 .shortname = "Xonar DS", 1066 .shortname = "Xonar DS",
1002 .longname = "Asus Virtuoso 200", 1067 .longname = "Asus Virtuoso 66",
1003 .chip = "AV200", 1068 .chip = "AV200",
1004 .init = xonar_ds_init, 1069 .init = xonar_ds_init,
1005 .control_filter = xonar_ds_control_filter,
1006 .mixer_init = xonar_ds_mixer_init, 1070 .mixer_init = xonar_ds_mixer_init,
1007 .cleanup = xonar_ds_cleanup, 1071 .cleanup = xonar_ds_cleanup,
1008 .suspend = xonar_ds_suspend, 1072 .suspend = xonar_ds_suspend,
@@ -1013,6 +1077,7 @@ static const struct oxygen_model model_xonar_ds = {
1013 .set_adc_params = set_wm8776_adc_params, 1077 .set_adc_params = set_wm8776_adc_params,
1014 .update_dac_volume = update_wm87x6_volume, 1078 .update_dac_volume = update_wm87x6_volume,
1015 .update_dac_mute = update_wm87x6_mute, 1079 .update_dac_mute = update_wm87x6_mute,
1080 .update_center_lfe_mix = update_wm8766_center_lfe_mix,
1016 .gpio_changed = xonar_ds_gpio_changed, 1081 .gpio_changed = xonar_ds_gpio_changed,
1017 .dac_tlv = wm87x6_dac_db_scale, 1082 .dac_tlv = wm87x6_dac_db_scale,
1018 .model_data_size = sizeof(struct xonar_wm87x6), 1083 .model_data_size = sizeof(struct xonar_wm87x6),