aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/Makefile11
-rw-r--r--sound/pci/hda/hda_codec.c68
-rw-r--r--sound/pci/hda/hda_intel.c33
-rw-r--r--sound/pci/hda/hda_local.h12
-rw-r--r--sound/pci/hda/hda_patch.h6
-rw-r--r--sound/pci/hda/patch_analog.c165
-rw-r--r--sound/pci/hda/patch_cmedia.c24
-rw-r--r--sound/pci/hda/patch_conexant.c1311
-rw-r--r--sound/pci/hda/patch_realtek.c2367
-rw-r--r--sound/pci/hda/patch_sigmatel.c692
-rw-r--r--sound/pci/hda/patch_via.c1396
11 files changed, 5460 insertions, 625 deletions
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index dbacba6177db..60d7b05a204a 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,5 +1,14 @@
1snd-hda-intel-objs := hda_intel.o 1snd-hda-intel-objs := hda_intel.o
2snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o 2snd-hda-codec-objs := hda_codec.o \
3 hda_generic.o \
4 patch_realtek.o \
5 patch_cmedia.o \
6 patch_analog.o \
7 patch_sigmatel.o \
8 patch_si3054.o \
9 patch_atihdmi.o \
10 patch_conexant.o \
11 patch_via.o
3ifdef CONFIG_PROC_FS 12ifdef CONFIG_PROC_FS
4snd-hda-codec-objs += hda_proc.o 13snd-hda-codec-objs += hda_proc.o
5endif 14endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 18bbc87e376f..8f34fb447983 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -52,6 +52,7 @@ struct hda_vendor_id {
52static struct hda_vendor_id hda_vendor_ids[] = { 52static struct hda_vendor_id hda_vendor_ids[] = {
53 { 0x10ec, "Realtek" }, 53 { 0x10ec, "Realtek" },
54 { 0x1057, "Motorola" }, 54 { 0x1057, "Motorola" },
55 { 0x1106, "VIA" },
55 { 0x11d4, "Analog Devices" }, 56 { 0x11d4, "Analog Devices" },
56 { 0x13f6, "C-Media" }, 57 { 0x13f6, "C-Media" },
57 { 0x14f1, "Conexant" }, 58 { 0x14f1, "Conexant" },
@@ -262,7 +263,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
262 unsol->queue[wp] = res; 263 unsol->queue[wp] = res;
263 unsol->queue[wp + 1] = res_ex; 264 unsol->queue[wp + 1] = res_ex;
264 265
265 queue_work(unsol->workq, &unsol->work); 266 schedule_work(&unsol->work);
266 267
267 return 0; 268 return 0;
268} 269}
@@ -309,12 +310,6 @@ static int init_unsol_queue(struct hda_bus *bus)
309 snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n"); 310 snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n");
310 return -ENOMEM; 311 return -ENOMEM;
311 } 312 }
312 unsol->workq = create_singlethread_workqueue("hda_codec");
313 if (! unsol->workq) {
314 snd_printk(KERN_ERR "hda_codec: can't create workqueue\n");
315 kfree(unsol);
316 return -ENOMEM;
317 }
318 INIT_WORK(&unsol->work, process_unsol_events); 313 INIT_WORK(&unsol->work, process_unsol_events);
319 unsol->bus = bus; 314 unsol->bus = bus;
320 bus->unsol = unsol; 315 bus->unsol = unsol;
@@ -333,7 +328,7 @@ static int snd_hda_bus_free(struct hda_bus *bus)
333 if (! bus) 328 if (! bus)
334 return 0; 329 return 0;
335 if (bus->unsol) { 330 if (bus->unsol) {
336 destroy_workqueue(bus->unsol->workq); 331 flush_scheduled_work();
337 kfree(bus->unsol); 332 kfree(bus->unsol);
338 } 333 }
339 list_for_each_safe(p, n, &bus->codec_list) { 334 list_for_each_safe(p, n, &bus->codec_list) {
@@ -1714,6 +1709,8 @@ EXPORT_SYMBOL(snd_hda_build_pcms);
1714/** 1709/**
1715 * snd_hda_check_board_config - compare the current codec with the config table 1710 * snd_hda_check_board_config - compare the current codec with the config table
1716 * @codec: the HDA codec 1711 * @codec: the HDA codec
1712 * @num_configs: number of config enums
1713 * @models: array of model name strings
1717 * @tbl: configuration table, terminated by null entries 1714 * @tbl: configuration table, terminated by null entries
1718 * 1715 *
1719 * Compares the modelname or PCI subsystem id of the current codec with the 1716 * Compares the modelname or PCI subsystem id of the current codec with the
@@ -1722,33 +1719,44 @@ EXPORT_SYMBOL(snd_hda_build_pcms);
1722 * 1719 *
1723 * If no entries are matching, the function returns a negative value. 1720 * If no entries are matching, the function returns a negative value.
1724 */ 1721 */
1725int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl) 1722int snd_hda_check_board_config(struct hda_codec *codec,
1726{ 1723 int num_configs, const char **models,
1727 const struct hda_board_config *c; 1724 const struct snd_pci_quirk *tbl)
1728 1725{
1729 if (codec->bus->modelname) { 1726 if (codec->bus->modelname && models) {
1730 for (c = tbl; c->modelname || c->pci_subvendor; c++) { 1727 int i;
1731 if (c->modelname && 1728 for (i = 0; i < num_configs; i++) {
1732 ! strcmp(codec->bus->modelname, c->modelname)) { 1729 if (models[i] &&
1733 snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname); 1730 !strcmp(codec->bus->modelname, models[i])) {
1734 return c->config; 1731 snd_printd(KERN_INFO "hda_codec: model '%s' is "
1732 "selected\n", models[i]);
1733 return i;
1735 } 1734 }
1736 } 1735 }
1737 } 1736 }
1738 1737
1739 if (codec->bus->pci) { 1738 if (!codec->bus->pci || !tbl)
1740 u16 subsystem_vendor, subsystem_device; 1739 return -1;
1741 pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); 1740
1742 pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); 1741 tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl);
1743 for (c = tbl; c->modelname || c->pci_subvendor; c++) { 1742 if (!tbl)
1744 if (c->pci_subvendor == subsystem_vendor && 1743 return -1;
1745 (! c->pci_subdevice /* all match */|| 1744 if (tbl->value >= 0 && tbl->value < num_configs) {
1746 (c->pci_subdevice == subsystem_device))) { 1745#ifdef CONFIG_SND_DEBUG_DETECT
1747 snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n", 1746 char tmp[10];
1748 subsystem_vendor, subsystem_device, c->config); 1747 const char *model = NULL;
1749 return c->config; 1748 if (models)
1750 } 1749 model = models[tbl->value];
1750 if (!model) {
1751 sprintf(tmp, "#%d", tbl->value);
1752 model = tmp;
1751 } 1753 }
1754 snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
1755 "for config %x:%x (%s)\n",
1756 model, tbl->subvendor, tbl->subdevice,
1757 (tbl->name ? tbl->name : "Unknown device"));
1758#endif
1759 return tbl->value;
1752 } 1760 }
1753 return -1; 1761 return -1;
1754} 1762}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1a7e82104bb9..b9a8e238b0a8 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -199,7 +199,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
199 199
200/* STATESTS int mask: SD2,SD1,SD0 */ 200/* STATESTS int mask: SD2,SD1,SD0 */
201#define STATESTS_INT_MASK 0x07 201#define STATESTS_INT_MASK 0x07
202#define AZX_MAX_CODECS 4 202#define AZX_MAX_CODECS 3
203 203
204/* SD_CTL bits */ 204/* SD_CTL bits */
205#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ 205#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
@@ -1285,7 +1285,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
1285 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); 1285 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
1286 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 1286 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1287 snd_dma_pci_data(chip->pci), 1287 snd_dma_pci_data(chip->pci),
1288 1024 * 64, 1024 * 128); 1288 1024 * 64, 1024 * 1024);
1289 chip->pcm[pcm_dev] = pcm; 1289 chip->pcm[pcm_dev] = pcm;
1290 if (chip->pcm_devs < pcm_dev + 1) 1290 if (chip->pcm_devs < pcm_dev + 1)
1291 chip->pcm_devs = pcm_dev + 1; 1291 chip->pcm_devs = pcm_dev + 1;
@@ -1391,6 +1391,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
1391 return -1; 1391 return -1;
1392 } 1392 }
1393 chip->irq = chip->pci->irq; 1393 chip->irq = chip->pci->irq;
1394 pci_intx(chip->pci, !chip->msi);
1394 return 0; 1395 return 0;
1395} 1396}
1396 1397
@@ -1502,6 +1503,31 @@ static int azx_dev_free(struct snd_device *device)
1502} 1503}
1503 1504
1504/* 1505/*
1506 * white/black-listing for position_fix
1507 */
1508static const struct snd_pci_quirk position_fix_list[] __devinitdata = {
1509 SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE),
1510 {}
1511};
1512
1513static int __devinit check_position_fix(struct azx *chip, int fix)
1514{
1515 const struct snd_pci_quirk *q;
1516
1517 if (fix == POS_FIX_AUTO) {
1518 q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
1519 if (q) {
1520 snd_printdd(KERN_INFO
1521 "hda_intel: position_fix set to %d "
1522 "for device %04x:%04x\n",
1523 q->value, q->subvendor, q->subdevice);
1524 return q->value;
1525 }
1526 }
1527 return fix;
1528}
1529
1530/*
1505 * constructor 1531 * constructor
1506 */ 1532 */
1507static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, 1533static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
@@ -1535,7 +1561,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
1535 chip->driver_type = driver_type; 1561 chip->driver_type = driver_type;
1536 chip->msi = enable_msi; 1562 chip->msi = enable_msi;
1537 1563
1538 chip->position_fix = position_fix; 1564 chip->position_fix = check_position_fix(chip, position_fix);
1565
1539 chip->single_cmd = single_cmd; 1566 chip->single_cmd = single_cmd;
1540 1567
1541#if BITS_PER_LONG != 64 1568#if BITS_PER_LONG != 64
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 9ca1baf860bd..39718d6cdadd 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -173,14 +173,9 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
173/* 173/*
174 * Misc 174 * Misc
175 */ 175 */
176struct hda_board_config { 176int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
177 const char *modelname; 177 const char **modelnames,
178 int config; 178 const struct snd_pci_quirk *pci_list);
179 unsigned short pci_subvendor;
180 unsigned short pci_subdevice;
181};
182
183int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl);
184int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); 179int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew);
185 180
186/* 181/*
@@ -204,7 +199,6 @@ struct hda_bus_unsolicited {
204 unsigned int rp, wp; 199 unsigned int rp, wp;
205 200
206 /* workqueue */ 201 /* workqueue */
207 struct workqueue_struct *workq;
208 struct work_struct work; 202 struct work_struct work;
209 struct hda_bus *bus; 203 struct hda_bus *bus;
210}; 204};
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index 0b668793face..9f9e9ae44a9d 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -14,6 +14,10 @@ extern struct hda_codec_preset snd_hda_preset_sigmatel[];
14extern struct hda_codec_preset snd_hda_preset_si3054[]; 14extern struct hda_codec_preset snd_hda_preset_si3054[];
15/* ATI HDMI codecs */ 15/* ATI HDMI codecs */
16extern struct hda_codec_preset snd_hda_preset_atihdmi[]; 16extern struct hda_codec_preset snd_hda_preset_atihdmi[];
17/* Conexant audio codec */
18extern struct hda_codec_preset snd_hda_preset_conexant[];
19/* VIA codecs */
20extern struct hda_codec_preset snd_hda_preset_via[];
17 21
18static const struct hda_codec_preset *hda_preset_tables[] = { 22static const struct hda_codec_preset *hda_preset_tables[] = {
19 snd_hda_preset_realtek, 23 snd_hda_preset_realtek,
@@ -22,5 +26,7 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
22 snd_hda_preset_sigmatel, 26 snd_hda_preset_sigmatel,
23 snd_hda_preset_si3054, 27 snd_hda_preset_si3054,
24 snd_hda_preset_atihdmi, 28 snd_hda_preset_atihdmi,
29 snd_hda_preset_conexant,
30 snd_hda_preset_via,
25 NULL 31 NULL
26}; 32};
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 076365bc10e9..38977bce70e2 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -782,54 +782,63 @@ static struct hda_channel_mode ad1986a_modes[3] = {
782 782
783/* eapd initialization */ 783/* eapd initialization */
784static struct hda_verb ad1986a_eapd_init_verbs[] = { 784static struct hda_verb ad1986a_eapd_init_verbs[] = {
785 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, 785 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
786 {} 786 {}
787}; 787};
788 788
789/* Ultra initialization */
790static struct hda_verb ad1986a_ultra_init[] = {
791 /* eapd initialization */
792 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
793 /* CLFE -> Mic in */
794 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
795 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
796 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
797 { } /* end */
798};
799
789/* models */ 800/* models */
790enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD }; 801enum {
791 802 AD1986A_6STACK,
792static struct hda_board_config ad1986a_cfg_tbl[] = { 803 AD1986A_3STACK,
793 { .modelname = "6stack", .config = AD1986A_6STACK }, 804 AD1986A_LAPTOP,
794 { .modelname = "3stack", .config = AD1986A_3STACK }, 805 AD1986A_LAPTOP_EAPD,
795 { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84, 806 AD1986A_ULTRA,
796 .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ 807 AD1986A_MODELS
797 { .pci_subvendor = 0x1043, .pci_subdevice = 0x817f, 808};
798 .config = AD1986A_3STACK }, /* ASUS P5P-L2 */ 809
799 { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3, 810static const char *ad1986a_models[AD1986A_MODELS] = {
800 .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ 811 [AD1986A_6STACK] = "6stack",
801 { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb, 812 [AD1986A_3STACK] = "3stack",
802 .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */ 813 [AD1986A_LAPTOP] = "laptop",
803 { .modelname = "laptop", .config = AD1986A_LAPTOP }, 814 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
804 { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, 815 [AD1986A_ULTRA] = "ultra",
805 .config = AD1986A_LAPTOP }, /* FSC V2060 */ 816};
806 { .pci_subvendor = 0x17c0, .pci_subdevice = 0x2017, 817
807 .config = AD1986A_LAPTOP }, /* Samsung M50 */ 818static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
808 { .pci_subvendor = 0x1043, .pci_subdevice = 0x818f, 819 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
809 .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */ 820 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
810 { .modelname = "laptop-eapd", .config = AD1986A_LAPTOP_EAPD }, 821 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
811 { .pci_subvendor = 0x144d, .pci_subdevice = 0xc023, 822 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
812 .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */ 823 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
813 { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, 824 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
814 .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ 825 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
815 { .pci_subvendor = 0x144d, .pci_subdevice = 0xc026, 826 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
816 .config = AD1986A_LAPTOP_EAPD }, /* Samsung X11-T2300 Culesa */ 827 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
817 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153, 828 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
818 .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */ 829 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
819 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, 830 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
820 .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */ 831 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
821 { .pci_subvendor = 0x1043, .pci_subdevice = 0x11f7, 832 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
822 .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5A */ 833 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
823 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1263, 834 SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD),
824 .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5F */ 835 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD),
825 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1297, 836 SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD),
826 .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */ 837 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
827 { .pci_subvendor = 0x1043, .pci_subdevice = 0x12b3, 838 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
828 .config = AD1986A_LAPTOP_EAPD }, /* ASUS V1j */ 839 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
829 { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af, 840 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD),
830 .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */ 841 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
831 { .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066,
832 .config = AD1986A_LAPTOP_EAPD }, /* Lenovo 3000 N100-07684JU */
833 {} 842 {}
834}; 843};
835 844
@@ -861,7 +870,9 @@ static int patch_ad1986a(struct hda_codec *codec)
861 codec->patch_ops = ad198x_patch_ops; 870 codec->patch_ops = ad198x_patch_ops;
862 871
863 /* override some parameters */ 872 /* override some parameters */
864 board_config = snd_hda_check_board_config(codec, ad1986a_cfg_tbl); 873 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
874 ad1986a_models,
875 ad1986a_cfg_tbl);
865 switch (board_config) { 876 switch (board_config) {
866 case AD1986A_3STACK: 877 case AD1986A_3STACK:
867 spec->num_mixers = 2; 878 spec->num_mixers = 2;
@@ -891,6 +902,15 @@ static int patch_ad1986a(struct hda_codec *codec)
891 spec->multiout.dig_out_nid = 0; 902 spec->multiout.dig_out_nid = 0;
892 spec->input_mux = &ad1986a_laptop_eapd_capture_source; 903 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
893 break; 904 break;
905 case AD1986A_ULTRA:
906 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
907 spec->num_init_verbs = 2;
908 spec->init_verbs[1] = ad1986a_ultra_init;
909 spec->multiout.max_channels = 2;
910 spec->multiout.num_dacs = 1;
911 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
912 spec->multiout.dig_out_nid = 0;
913 break;
894 } 914 }
895 915
896 return 0; 916 return 0;
@@ -1391,20 +1411,27 @@ static struct hda_input_mux ad1981_thinkpad_capture_source = {
1391}; 1411};
1392 1412
1393/* models */ 1413/* models */
1394enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD }; 1414enum {
1415 AD1981_BASIC,
1416 AD1981_HP,
1417 AD1981_THINKPAD,
1418 AD1981_MODELS
1419};
1420
1421static const char *ad1981_models[AD1981_MODELS] = {
1422 [AD1981_HP] = "hp",
1423 [AD1981_THINKPAD] = "thinkpad",
1424 [AD1981_BASIC] = "basic",
1425};
1395 1426
1396static struct hda_board_config ad1981_cfg_tbl[] = { 1427static struct snd_pci_quirk ad1981_cfg_tbl[] = {
1397 { .modelname = "hp", .config = AD1981_HP },
1398 /* All HP models */ 1428 /* All HP models */
1399 { .pci_subvendor = 0x103c, .config = AD1981_HP }, 1429 SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
1400 { .pci_subvendor = 0x30b0, .pci_subdevice = 0x103c, 1430 /* HP nx6320 (reversed SSID, H/W bug) */
1401 .config = AD1981_HP }, /* HP nx6320 (reversed SSID, H/W bug) */ 1431 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
1402 { .modelname = "thinkpad", .config = AD1981_THINKPAD },
1403 /* Lenovo Thinkpad T60/X60/Z6xx */ 1432 /* Lenovo Thinkpad T60/X60/Z6xx */
1404 { .pci_subvendor = 0x17aa, .config = AD1981_THINKPAD }, 1433 SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
1405 { .pci_subvendor = 0x1014, .pci_subdevice = 0x0597, 1434 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
1406 .config = AD1981_THINKPAD }, /* Z60m/t */
1407 { .modelname = "basic", .config = AD1981_BASIC },
1408 {} 1435 {}
1409}; 1436};
1410 1437
@@ -1437,7 +1464,9 @@ static int patch_ad1981(struct hda_codec *codec)
1437 codec->patch_ops = ad198x_patch_ops; 1464 codec->patch_ops = ad198x_patch_ops;
1438 1465
1439 /* override some parameters */ 1466 /* override some parameters */
1440 board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl); 1467 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
1468 ad1981_models,
1469 ad1981_cfg_tbl);
1441 switch (board_config) { 1470 switch (board_config) {
1442 case AD1981_HP: 1471 case AD1981_HP:
1443 spec->mixers[0] = ad1981_hp_mixers; 1472 spec->mixers[0] = ad1981_hp_mixers;
@@ -2565,15 +2594,14 @@ static int ad1988_auto_init(struct hda_codec *codec)
2565/* 2594/*
2566 */ 2595 */
2567 2596
2568static struct hda_board_config ad1988_cfg_tbl[] = { 2597static const char *ad1988_models[AD1988_MODEL_LAST] = {
2569 { .modelname = "6stack", .config = AD1988_6STACK }, 2598 [AD1988_6STACK] = "6stack",
2570 { .modelname = "6stack-dig", .config = AD1988_6STACK_DIG }, 2599 [AD1988_6STACK_DIG] = "6stack-dig",
2571 { .modelname = "3stack", .config = AD1988_3STACK }, 2600 [AD1988_3STACK] = "3stack",
2572 { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG }, 2601 [AD1988_3STACK_DIG] = "3stack-dig",
2573 { .modelname = "laptop", .config = AD1988_LAPTOP }, 2602 [AD1988_LAPTOP] = "laptop",
2574 { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG }, 2603 [AD1988_LAPTOP_DIG] = "laptop-dig",
2575 { .modelname = "auto", .config = AD1988_AUTO }, 2604 [AD1988_AUTO] = "auto",
2576 {}
2577}; 2605};
2578 2606
2579static int patch_ad1988(struct hda_codec *codec) 2607static int patch_ad1988(struct hda_codec *codec)
@@ -2591,8 +2619,9 @@ static int patch_ad1988(struct hda_codec *codec)
2591 if (is_rev2(codec)) 2619 if (is_rev2(codec))
2592 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); 2620 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
2593 2621
2594 board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl); 2622 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
2595 if (board_config < 0 || board_config >= AD1988_MODEL_LAST) { 2623 ad1988_models, NULL);
2624 if (board_config < 0) {
2596 printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n"); 2625 printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");
2597 board_config = AD1988_AUTO; 2626 board_config = AD1988_AUTO;
2598 } 2627 }
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index d38ce22507ae..5b9d3a31a1ae 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -40,6 +40,7 @@ enum {
40 CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ 40 CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */
41 CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ 41 CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */
42 CMI_AUTO, /* let driver guess it */ 42 CMI_AUTO, /* let driver guess it */
43 CMI_MODELS
43}; 44};
44 45
45struct cmi_spec { 46struct cmi_spec {
@@ -603,14 +604,17 @@ static void cmi9880_free(struct hda_codec *codec)
603/* 604/*
604 */ 605 */
605 606
606static struct hda_board_config cmi9880_cfg_tbl[] = { 607static const char *cmi9880_models[CMI_MODELS] = {
607 { .modelname = "minimal", .config = CMI_MINIMAL }, 608 [CMI_MINIMAL] = "minimal",
608 { .modelname = "min_fp", .config = CMI_MIN_FP }, 609 [CMI_MIN_FP] = "min_fp",
609 { .modelname = "full", .config = CMI_FULL }, 610 [CMI_FULL] = "full",
610 { .modelname = "full_dig", .config = CMI_FULL_DIG }, 611 [CMI_FULL_DIG] = "full_dig",
611 { .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */ 612 [CMI_ALLOUT] = "allout",
612 { .modelname = "allout", .config = CMI_ALLOUT }, 613 [CMI_AUTO] = "auto",
613 { .modelname = "auto", .config = CMI_AUTO }, 614};
615
616static struct snd_pci_quirk cmi9880_cfg_tbl[] = {
617 SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG),
614 {} /* terminator */ 618 {} /* terminator */
615}; 619};
616 620
@@ -633,7 +637,9 @@ static int patch_cmi9880(struct hda_codec *codec)
633 return -ENOMEM; 637 return -ENOMEM;
634 638
635 codec->spec = spec; 639 codec->spec = spec;
636 spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); 640 spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS,
641 cmi9880_models,
642 cmi9880_cfg_tbl);
637 if (spec->board_config < 0) { 643 if (spec->board_config < 0) {
638 snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); 644 snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
639 spec->board_config = CMI_AUTO; /* try everything */ 645 spec->board_config = CMI_AUTO; /* try everything */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
new file mode 100644
index 000000000000..73f4668238c6
--- /dev/null
+++ b/sound/pci/hda/patch_conexant.c
@@ -0,0 +1,1311 @@
1/*
2 * HD audio interface patch for Conexant HDA audio codec
3 *
4 * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
5 * Takashi Iwai <tiwai@suse.de>
6 * Tobin Davis <tdavis@dsl-only.net>
7 *
8 * This driver is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This driver is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <sound/driver.h>
24#include <linux/init.h>
25#include <linux/delay.h>
26#include <linux/slab.h>
27#include <linux/pci.h>
28#include <sound/core.h>
29#include "hda_codec.h"
30#include "hda_local.h"
31
32#define CXT_PIN_DIR_IN 0x00
33#define CXT_PIN_DIR_OUT 0x01
34#define CXT_PIN_DIR_INOUT 0x02
35#define CXT_PIN_DIR_IN_NOMICBIAS 0x03
36#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04
37
38#define CONEXANT_HP_EVENT 0x37
39#define CONEXANT_MIC_EVENT 0x38
40
41
42
43struct conexant_spec {
44
45 struct snd_kcontrol_new *mixers[5];
46 int num_mixers;
47
48 const struct hda_verb *init_verbs[5]; /* initialization verbs
49 * don't forget NULL
50 * termination!
51 */
52 unsigned int num_init_verbs;
53
54 /* playback */
55 struct hda_multi_out multiout; /* playback set-up
56 * max_channels, dacs must be set
57 * dig_out_nid and hp_nid are optional
58 */
59 unsigned int cur_eapd;
60 unsigned int need_dac_fix;
61
62 /* capture */
63 unsigned int num_adc_nids;
64 hda_nid_t *adc_nids;
65 hda_nid_t dig_in_nid; /* digital-in NID; optional */
66
67 /* capture source */
68 const struct hda_input_mux *input_mux;
69 hda_nid_t *capsrc_nids;
70 unsigned int cur_mux[3];
71
72 /* channel model */
73 const struct hda_channel_mode *channel_mode;
74 int num_channel_mode;
75
76 /* PCM information */
77 struct hda_pcm pcm_rec[2]; /* used in build_pcms() */
78
79 struct mutex amp_mutex; /* PCM volume/mute control mutex */
80 unsigned int spdif_route;
81
82 /* dynamic controls, init_verbs and input_mux */
83 struct auto_pin_cfg autocfg;
84 unsigned int num_kctl_alloc, num_kctl_used;
85 struct snd_kcontrol_new *kctl_alloc;
86 struct hda_input_mux private_imux;
87 hda_nid_t private_dac_nids[4];
88
89};
90
91static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
92 struct hda_codec *codec,
93 struct snd_pcm_substream *substream)
94{
95 struct conexant_spec *spec = codec->spec;
96 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
97}
98
99static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
100 struct hda_codec *codec,
101 unsigned int stream_tag,
102 unsigned int format,
103 struct snd_pcm_substream *substream)
104{
105 struct conexant_spec *spec = codec->spec;
106 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
107 stream_tag,
108 format, substream);
109}
110
111static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
112 struct hda_codec *codec,
113 struct snd_pcm_substream *substream)
114{
115 struct conexant_spec *spec = codec->spec;
116 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
117}
118
119/*
120 * Digital out
121 */
122static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
123 struct hda_codec *codec,
124 struct snd_pcm_substream *substream)
125{
126 struct conexant_spec *spec = codec->spec;
127 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
128}
129
130static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
131 struct hda_codec *codec,
132 struct snd_pcm_substream *substream)
133{
134 struct conexant_spec *spec = codec->spec;
135 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
136}
137
138/*
139 * Analog capture
140 */
141static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
142 struct hda_codec *codec,
143 unsigned int stream_tag,
144 unsigned int format,
145 struct snd_pcm_substream *substream)
146{
147 struct conexant_spec *spec = codec->spec;
148 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
149 stream_tag, 0, format);
150 return 0;
151}
152
153static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
154 struct hda_codec *codec,
155 struct snd_pcm_substream *substream)
156{
157 struct conexant_spec *spec = codec->spec;
158 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
159 0, 0, 0);
160 return 0;
161}
162
163
164
165static struct hda_pcm_stream conexant_pcm_analog_playback = {
166 .substreams = 1,
167 .channels_min = 2,
168 .channels_max = 2,
169 .nid = 0, /* fill later */
170 .ops = {
171 .open = conexant_playback_pcm_open,
172 .prepare = conexant_playback_pcm_prepare,
173 .cleanup = conexant_playback_pcm_cleanup
174 },
175};
176
177static struct hda_pcm_stream conexant_pcm_analog_capture = {
178 .substreams = 1,
179 .channels_min = 2,
180 .channels_max = 2,
181 .nid = 0, /* fill later */
182 .ops = {
183 .prepare = conexant_capture_pcm_prepare,
184 .cleanup = conexant_capture_pcm_cleanup
185 },
186};
187
188
189static struct hda_pcm_stream conexant_pcm_digital_playback = {
190 .substreams = 1,
191 .channels_min = 2,
192 .channels_max = 2,
193 .nid = 0, /* fill later */
194 .ops = {
195 .open = conexant_dig_playback_pcm_open,
196 .close = conexant_dig_playback_pcm_close
197 },
198};
199
200static struct hda_pcm_stream conexant_pcm_digital_capture = {
201 .substreams = 1,
202 .channels_min = 2,
203 .channels_max = 2,
204 /* NID is set in alc_build_pcms */
205};
206
207static int conexant_build_pcms(struct hda_codec *codec)
208{
209 struct conexant_spec *spec = codec->spec;
210 struct hda_pcm *info = spec->pcm_rec;
211
212 codec->num_pcms = 1;
213 codec->pcm_info = info;
214
215 info->name = "CONEXANT Analog";
216 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback;
217 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
218 spec->multiout.max_channels;
219 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
220 spec->multiout.dac_nids[0];
221 info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture;
222 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
223 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
224
225 if (spec->multiout.dig_out_nid) {
226 info++;
227 codec->num_pcms++;
228 info->name = "Conexant Digital";
229 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
230 conexant_pcm_digital_playback;
231 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
232 spec->multiout.dig_out_nid;
233 if (spec->dig_in_nid) {
234 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
235 conexant_pcm_digital_capture;
236 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
237 spec->dig_in_nid;
238 }
239 }
240
241 return 0;
242}
243
244static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol,
245 struct snd_ctl_elem_info *uinfo)
246{
247 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
248 struct conexant_spec *spec = codec->spec;
249
250 return snd_hda_input_mux_info(spec->input_mux, uinfo);
251}
252
253static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol,
254 struct snd_ctl_elem_value *ucontrol)
255{
256 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
257 struct conexant_spec *spec = codec->spec;
258 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
259
260 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
261 return 0;
262}
263
264static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
265 struct snd_ctl_elem_value *ucontrol)
266{
267 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
268 struct conexant_spec *spec = codec->spec;
269 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
270
271 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
272 spec->capsrc_nids[adc_idx],
273 &spec->cur_mux[adc_idx]);
274}
275
276static int conexant_init(struct hda_codec *codec)
277{
278 struct conexant_spec *spec = codec->spec;
279 int i;
280
281 for (i = 0; i < spec->num_init_verbs; i++)
282 snd_hda_sequence_write(codec, spec->init_verbs[i]);
283 return 0;
284}
285
286static void conexant_free(struct hda_codec *codec)
287{
288 struct conexant_spec *spec = codec->spec;
289 unsigned int i;
290
291 if (spec->kctl_alloc) {
292 for (i = 0; i < spec->num_kctl_used; i++)
293 kfree(spec->kctl_alloc[i].name);
294 kfree(spec->kctl_alloc);
295 }
296
297 kfree(codec->spec);
298}
299
300#ifdef CONFIG_PM
301static int conexant_resume(struct hda_codec *codec)
302{
303 struct conexant_spec *spec = codec->spec;
304 int i;
305
306 codec->patch_ops.init(codec);
307 for (i = 0; i < spec->num_mixers; i++)
308 snd_hda_resume_ctls(codec, spec->mixers[i]);
309 if (spec->multiout.dig_out_nid)
310 snd_hda_resume_spdif_out(codec);
311 if (spec->dig_in_nid)
312 snd_hda_resume_spdif_in(codec);
313 return 0;
314}
315#endif
316
317static int conexant_build_controls(struct hda_codec *codec)
318{
319 struct conexant_spec *spec = codec->spec;
320 unsigned int i;
321 int err;
322
323 for (i = 0; i < spec->num_mixers; i++) {
324 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
325 if (err < 0)
326 return err;
327 }
328 if (spec->multiout.dig_out_nid) {
329 err = snd_hda_create_spdif_out_ctls(codec,
330 spec->multiout.dig_out_nid);
331 if (err < 0)
332 return err;
333 }
334 if (spec->dig_in_nid) {
335 err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid);
336 if (err < 0)
337 return err;
338 }
339 return 0;
340}
341
342static struct hda_codec_ops conexant_patch_ops = {
343 .build_controls = conexant_build_controls,
344 .build_pcms = conexant_build_pcms,
345 .init = conexant_init,
346 .free = conexant_free,
347#ifdef CONFIG_PM
348 .resume = conexant_resume,
349#endif
350};
351
352/*
353 * EAPD control
354 * the private value = nid | (invert << 8)
355 */
356
357static int conexant_eapd_info(struct snd_kcontrol *kcontrol,
358 struct snd_ctl_elem_info *uinfo)
359{
360 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
361 uinfo->count = 1;
362 uinfo->value.integer.min = 0;
363 uinfo->value.integer.max = 1;
364 return 0;
365}
366
367static int conexant_eapd_get(struct snd_kcontrol *kcontrol,
368 struct snd_ctl_elem_value *ucontrol)
369{
370 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
371 struct conexant_spec *spec = codec->spec;
372 int invert = (kcontrol->private_value >> 8) & 1;
373 if (invert)
374 ucontrol->value.integer.value[0] = !spec->cur_eapd;
375 else
376 ucontrol->value.integer.value[0] = spec->cur_eapd;
377 return 0;
378}
379
380static int conexant_eapd_put(struct snd_kcontrol *kcontrol,
381 struct snd_ctl_elem_value *ucontrol)
382{
383 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
384 struct conexant_spec *spec = codec->spec;
385 int invert = (kcontrol->private_value >> 8) & 1;
386 hda_nid_t nid = kcontrol->private_value & 0xff;
387 unsigned int eapd;
388 eapd = ucontrol->value.integer.value[0];
389 if (invert)
390 eapd = !eapd;
391 if (eapd == spec->cur_eapd && !codec->in_resume)
392 return 0;
393 spec->cur_eapd = eapd;
394 snd_hda_codec_write(codec, nid,
395 0, AC_VERB_SET_EAPD_BTLENABLE,
396 eapd ? 0x02 : 0x00);
397 return 1;
398}
399
400/* controls for test mode */
401#ifdef CONFIG_SND_DEBUG
402
403static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol,
404 struct snd_ctl_elem_info *uinfo)
405{
406 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
407 struct conexant_spec *spec = codec->spec;
408 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
409 spec->num_channel_mode);
410}
411
412static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol,
413 struct snd_ctl_elem_value *ucontrol)
414{
415 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
416 struct conexant_spec *spec = codec->spec;
417 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
418 spec->num_channel_mode,
419 spec->multiout.max_channels);
420}
421
422static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol,
423 struct snd_ctl_elem_value *ucontrol)
424{
425 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
426 struct conexant_spec *spec = codec->spec;
427 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
428 spec->num_channel_mode,
429 &spec->multiout.max_channels);
430 if (err >= 0 && spec->need_dac_fix)
431 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
432 return err;
433}
434
435#define CXT_PIN_MODE(xname, nid, dir) \
436 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
437 .info = conexant_ch_mode_info, \
438 .get = conexant_ch_mode_get, \
439 .put = conexant_ch_mode_put, \
440 .private_value = nid | (dir<<16) }
441
442static int cxt_gpio_data_info(struct snd_kcontrol *kcontrol,
443 struct snd_ctl_elem_info *uinfo)
444{
445 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
446 uinfo->count = 1;
447 uinfo->value.integer.min = 0;
448 uinfo->value.integer.max = 1;
449 return 0;
450}
451
452static int cxt_gpio_data_get(struct snd_kcontrol *kcontrol,
453 struct snd_ctl_elem_value *ucontrol)
454{
455 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
456 hda_nid_t nid = kcontrol->private_value & 0xffff;
457 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
458 long *valp = ucontrol->value.integer.value;
459 unsigned int val = snd_hda_codec_read(codec, nid, 0,
460 AC_VERB_GET_GPIO_DATA, 0x00);
461
462 *valp = (val & mask) != 0;
463 return 0;
464}
465
466static int cxt_gpio_data_put(struct snd_kcontrol *kcontrol,
467 struct snd_ctl_elem_value *ucontrol)
468{
469 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
470 hda_nid_t nid = kcontrol->private_value & 0xffff;
471 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
472 long val = *ucontrol->value.integer.value;
473 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
474 AC_VERB_GET_GPIO_DATA,
475 0x00);
476 unsigned int old_data = gpio_data;
477
478 /* Set/unset the masked GPIO bit(s) as needed */
479 if (val == 0)
480 gpio_data &= ~mask;
481 else
482 gpio_data |= mask;
483 if (gpio_data == old_data && !codec->in_resume)
484 return 0;
485 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data);
486 return 1;
487}
488
489#define CXT_GPIO_DATA_SWITCH(xname, nid, mask) \
490 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
491 .info = cxt_gpio_data_info, \
492 .get = cxt_gpio_data_get, \
493 .put = cxt_gpio_data_put, \
494 .private_value = nid | (mask<<16) }
495
496static int cxt_spdif_ctrl_info(struct snd_kcontrol *kcontrol,
497 struct snd_ctl_elem_info *uinfo)
498{
499 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
500 uinfo->count = 1;
501 uinfo->value.integer.min = 0;
502 uinfo->value.integer.max = 1;
503 return 0;
504}
505
506static int cxt_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
507 struct snd_ctl_elem_value *ucontrol)
508{
509 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
510 hda_nid_t nid = kcontrol->private_value & 0xffff;
511 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
512 long *valp = ucontrol->value.integer.value;
513 unsigned int val = snd_hda_codec_read(codec, nid, 0,
514 AC_VERB_GET_DIGI_CONVERT, 0x00);
515
516 *valp = (val & mask) != 0;
517 return 0;
518}
519
520static int cxt_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
521 struct snd_ctl_elem_value *ucontrol)
522{
523 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
524 hda_nid_t nid = kcontrol->private_value & 0xffff;
525 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
526 long val = *ucontrol->value.integer.value;
527 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
528 AC_VERB_GET_DIGI_CONVERT,
529 0x00);
530 unsigned int old_data = ctrl_data;
531
532 /* Set/unset the masked control bit(s) as needed */
533 if (val == 0)
534 ctrl_data &= ~mask;
535 else
536 ctrl_data |= mask;
537 if (ctrl_data == old_data && !codec->in_resume)
538 return 0;
539 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
540 ctrl_data);
541 return 1;
542}
543
544#define CXT_SPDIF_CTRL_SWITCH(xname, nid, mask) \
545 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
546 .info = cxt_spdif_ctrl_info, \
547 .get = cxt_spdif_ctrl_get, \
548 .put = cxt_spdif_ctrl_put, \
549 .private_value = nid | (mask<<16) }
550
551#endif /* CONFIG_SND_DEBUG */
552
553/* Conexant 5045 specific */
554
555static hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
556static hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
557static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
558#define CXT5045_SPDIF_OUT 0x13
559
560static struct hda_channel_mode cxt5045_modes[1] = {
561 { 2, NULL },
562};
563
564static struct hda_input_mux cxt5045_capture_source = {
565 .num_items = 2,
566 .items = {
567 { "ExtMic", 0x1 },
568 { "LineIn", 0x2 },
569 }
570};
571
572/* turn on/off EAPD (+ mute HP) as a master switch */
573static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
574 struct snd_ctl_elem_value *ucontrol)
575{
576 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
577 struct conexant_spec *spec = codec->spec;
578
579 if (!conexant_eapd_put(kcontrol, ucontrol))
580 return 0;
581
582 /* toggle HP mute appropriately */
583 snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0,
584 0x80, spec->cur_eapd ? 0 : 0x80);
585 snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0,
586 0x80, spec->cur_eapd ? 0 : 0x80);
587 return 1;
588}
589
590/* bind volumes of both NID 0x10 and 0x11 */
591static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol,
592 struct snd_ctl_elem_value *ucontrol)
593{
594 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
595 long *valp = ucontrol->value.integer.value;
596 int change;
597
598 change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0,
599 0x7f, valp[0] & 0x7f);
600 change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0,
601 0x7f, valp[1] & 0x7f);
602 snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0,
603 0x7f, valp[0] & 0x7f);
604 snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0,
605 0x7f, valp[1] & 0x7f);
606 return change;
607}
608
609
610/* mute internal speaker if HP is plugged */
611static void cxt5045_hp_automute(struct hda_codec *codec)
612{
613 unsigned int present;
614
615 present = snd_hda_codec_read(codec, 0x11, 0,
616 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
617 snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0,
618 0x80, present ? 0x80 : 0);
619 snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0,
620 0x80, present ? 0x80 : 0);
621}
622
623/* unsolicited event for HP jack sensing */
624static void cxt5045_hp_unsol_event(struct hda_codec *codec,
625 unsigned int res)
626{
627 res >>= 26;
628 switch (res) {
629 case CONEXANT_HP_EVENT:
630 cxt5045_hp_automute(codec);
631 break;
632 }
633}
634
635static struct snd_kcontrol_new cxt5045_mixers[] = {
636 {
637 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
638 .name = "Capture Source",
639 .info = conexant_mux_enum_info,
640 .get = conexant_mux_enum_get,
641 .put = conexant_mux_enum_put
642 },
643 HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x17, 0x02, HDA_INPUT),
644 HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x17, 0x02, HDA_INPUT),
645 HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x02, HDA_INPUT),
646 HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x02, HDA_INPUT),
647 {
648 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
649 .name = "Master Playback Volume",
650 .info = snd_hda_mixer_amp_volume_info,
651 .get = snd_hda_mixer_amp_volume_get,
652 .put = cxt5045_hp_master_vol_put,
653 .private_value = HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
654 },
655 {
656 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
657 .name = "Master Playback Switch",
658 .info = conexant_eapd_info,
659 .get = conexant_eapd_get,
660 .put = cxt5045_hp_master_sw_put,
661 .private_value = 0x11,
662 },
663
664 {}
665};
666
667static struct hda_verb cxt5045_init_verbs[] = {
668 /* Line in, Mic */
669 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
670 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
671 /* HP, Amp */
672 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
673 {0x1A, AC_VERB_SET_CONNECT_SEL,0x01},
674 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
675 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
676 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
677 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
678 /* Record selector: Front mic */
679 {0x14, AC_VERB_SET_CONNECT_SEL,0x03},
680 {0x17, AC_VERB_SET_AMP_GAIN_MUTE,
681 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
682 /* SPDIF route: PCM */
683 { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 },
684 /* pin sensing on HP and Mic jacks */
685 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
686 /* EAPD */
687 {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
688 { } /* end */
689};
690
691#ifdef CONFIG_SND_DEBUG
692/* Test configuration for debugging, modelled after the ALC260 test
693 * configuration.
694 */
695static struct hda_input_mux cxt5045_test_capture_source = {
696 .num_items = 5,
697 .items = {
698 { "MIXER", 0x0 },
699 { "MIC1 pin", 0x1 },
700 { "LINE1 pin", 0x2 },
701 { "HP-OUT pin", 0x3 },
702 { "CD pin", 0x4 },
703 },
704};
705
706static struct snd_kcontrol_new cxt5045_test_mixer[] = {
707
708 /* Output controls */
709 HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x19, 0x00, HDA_OUTPUT),
710 HDA_CODEC_MUTE("OutAmp-1 Switch", 0x19,0x00, HDA_OUTPUT),
711 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT),
712 HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT),
713
714 /* Modes for retasking pin widgets */
715 CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT),
716 CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT),
717
718 /* Loopback mixer controls */
719 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x17, 0x01, HDA_INPUT),
720 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x17, 0x01, HDA_INPUT),
721 HDA_CODEC_VOLUME("LINE loopback Playback Volume", 0x17, 0x02, HDA_INPUT),
722 HDA_CODEC_MUTE("LINE loopback Playback Switch", 0x17, 0x02, HDA_INPUT),
723 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x17, 0x03, HDA_INPUT),
724 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x17, 0x03, HDA_INPUT),
725 HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x04, HDA_INPUT),
726 HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x04, HDA_INPUT),
727
728 /* Controls for GPIO pins, assuming they exist and are configured as outputs */
729 CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
730#if 0 /* limit this to one GPIO pin for now */
731 CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
732 CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
733 CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
734#endif
735 CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x13, 0x01),
736
737 HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_OUTPUT),
738 HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_OUTPUT),
739 {
740 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
741 .name = "Input Source",
742 .info = conexant_mux_enum_info,
743 .get = conexant_mux_enum_get,
744 .put = conexant_mux_enum_put,
745 },
746
747 { } /* end */
748};
749
750static struct hda_verb cxt5045_test_init_verbs[] = {
751 /* Enable all GPIOs as outputs with an initial value of 0 */
752 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
753 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
754 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
755
756 /* Enable retasking pins as output, initially without power amp */
757 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
758 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
759
760 /* Disable digital (SPDIF) pins initially, but users can enable
761 * them via a mixer switch. In the case of SPDIF-out, this initverb
762 * payload also sets the generation to 0, output to be in "consumer"
763 * PCM format, copyright asserted, no pre-emphasis and no validity
764 * control.
765 */
766 {0x13, AC_VERB_SET_DIGI_CONVERT_1, 0},
767
768 /* Start with output sum widgets muted and their output gains at min */
769 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
770 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
771
772 /* Unmute retasking pin widget output buffers since the default
773 * state appears to be output. As the pin mode is changed by the
774 * user the pin mode control will take care of enabling the pin's
775 * input/output buffers as needed.
776 */
777 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
778 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
779
780 /* Mute capture amp left and right */
781 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
782
783 /* Set ADC connection select to match default mixer setting (mic1
784 * pin)
785 */
786 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
787
788 /* Mute all inputs to mixer widget (even unconnected ones) */
789 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */
790 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */
791 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */
792 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */
793 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
794
795 { }
796};
797#endif
798
799
800/* initialize jack-sensing, too */
801static int cxt5045_init(struct hda_codec *codec)
802{
803 conexant_init(codec);
804 cxt5045_hp_automute(codec);
805 return 0;
806}
807
808
809enum {
810 CXT5045_LAPTOP, /* Laptops w/ EAPD support */
811#ifdef CONFIG_SND_DEBUG
812 CXT5045_TEST,
813#endif
814 CXT5045_MODELS
815};
816
817static const char *cxt5045_models[CXT5045_MODELS] = {
818 [CXT5045_LAPTOP] = "laptop",
819#ifdef CONFIG_SND_DEBUG
820 [CXT5045_TEST] = "test",
821#endif
822};
823
824static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
825 SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP),
826 {}
827};
828
829static int patch_cxt5045(struct hda_codec *codec)
830{
831 struct conexant_spec *spec;
832 int board_config;
833
834 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
835 if (!spec)
836 return -ENOMEM;
837 mutex_init(&spec->amp_mutex);
838 codec->spec = spec;
839
840 spec->multiout.max_channels = 2;
841 spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids);
842 spec->multiout.dac_nids = cxt5045_dac_nids;
843 spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT;
844 spec->num_adc_nids = 1;
845 spec->adc_nids = cxt5045_adc_nids;
846 spec->capsrc_nids = cxt5045_capsrc_nids;
847 spec->input_mux = &cxt5045_capture_source;
848 spec->num_mixers = 1;
849 spec->mixers[0] = cxt5045_mixers;
850 spec->num_init_verbs = 1;
851 spec->init_verbs[0] = cxt5045_init_verbs;
852 spec->spdif_route = 0;
853 spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes),
854 spec->channel_mode = cxt5045_modes,
855
856
857 codec->patch_ops = conexant_patch_ops;
858 codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
859
860 board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
861 cxt5045_models,
862 cxt5045_cfg_tbl);
863 switch (board_config) {
864 case CXT5045_LAPTOP:
865 spec->input_mux = &cxt5045_capture_source;
866 spec->num_init_verbs = 2;
867 spec->init_verbs[1] = cxt5045_init_verbs;
868 spec->mixers[0] = cxt5045_mixers;
869 codec->patch_ops.init = cxt5045_init;
870 break;
871#ifdef CONFIG_SND_DEBUG
872 case CXT5045_TEST:
873 spec->input_mux = &cxt5045_test_capture_source;
874 spec->mixers[0] = cxt5045_test_mixer;
875 spec->init_verbs[0] = cxt5045_test_init_verbs;
876#endif
877 }
878 return 0;
879}
880
881
882/* Conexant 5047 specific */
883
884static hda_nid_t cxt5047_dac_nids[1] = { 0x10 };
885static hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
886static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
887#define CXT5047_SPDIF_OUT 0x11
888
889static struct hda_channel_mode cxt5047_modes[1] = {
890 { 2, NULL },
891};
892
893static struct hda_input_mux cxt5047_capture_source = {
894 .num_items = 2,
895 .items = {
896 { "ExtMic", 0x1 },
897 { "IntMic", 0x2 },
898 }
899};
900
901static struct hda_input_mux cxt5047_hp_capture_source = {
902 .num_items = 1,
903 .items = {
904 { "ExtMic", 0x1 },
905 }
906};
907
908/* turn on/off EAPD (+ mute HP) as a master switch */
909static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol,
910 struct snd_ctl_elem_value *ucontrol)
911{
912 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
913 struct conexant_spec *spec = codec->spec;
914
915 if (!conexant_eapd_put(kcontrol, ucontrol))
916 return 0;
917
918 /* toggle HP mute appropriately */
919 snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0,
920 0x80, spec->cur_eapd ? 0 : 0x80);
921 snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0,
922 0x80, spec->cur_eapd ? 0 : 0x80);
923 return 1;
924}
925
926#if 0
927/* bind volumes of both NID 0x13 and 0x1d */
928static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol,
929 struct snd_ctl_elem_value *ucontrol)
930{
931 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
932 long *valp = ucontrol->value.integer.value;
933 int change;
934
935 change = snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0,
936 0x7f, valp[0] & 0x7f);
937 change |= snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0,
938 0x7f, valp[1] & 0x7f);
939 snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0,
940 0x7f, valp[0] & 0x7f);
941 snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0,
942 0x7f, valp[1] & 0x7f);
943 return change;
944}
945#endif
946
947/* mute internal speaker if HP is plugged */
948static void cxt5047_hp_automute(struct hda_codec *codec)
949{
950 unsigned int present;
951
952 present = snd_hda_codec_read(codec, 0x13, 0,
953 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
954 snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0,
955 0x80, present ? 0x80 : 0);
956 snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0,
957 0x80, present ? 0x80 : 0);
958}
959
960/* toggle input of built-in and mic jack appropriately */
961static void cxt5047_hp_automic(struct hda_codec *codec)
962{
963 static struct hda_verb mic_jack_on[] = {
964 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
965 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
966 {}
967 };
968 static struct hda_verb mic_jack_off[] = {
969 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
970 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
971 {}
972 };
973 unsigned int present;
974
975 present = snd_hda_codec_read(codec, 0x08, 0,
976 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
977 if (present)
978 snd_hda_sequence_write(codec, mic_jack_on);
979 else
980 snd_hda_sequence_write(codec, mic_jack_off);
981}
982
983/* unsolicited event for HP jack sensing */
984static void cxt5047_hp_unsol_event(struct hda_codec *codec,
985 unsigned int res)
986{
987 res >>= 26;
988 switch (res) {
989 case CONEXANT_HP_EVENT:
990 cxt5047_hp_automute(codec);
991 break;
992 case CONEXANT_MIC_EVENT:
993 cxt5047_hp_automic(codec);
994 break;
995 }
996}
997
998static struct snd_kcontrol_new cxt5047_mixers[] = {
999 {
1000 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1001 .name = "Capture Source",
1002 .info = conexant_mux_enum_info,
1003 .get = conexant_mux_enum_get,
1004 .put = conexant_mux_enum_put
1005 },
1006 HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
1007 HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT),
1008 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
1009 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
1010 HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
1011 HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
1012 HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
1013 {
1014 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1015 .name = "Master Playback Switch",
1016 .info = conexant_eapd_info,
1017 .get = conexant_eapd_get,
1018 .put = cxt5047_hp_master_sw_put,
1019 .private_value = 0x13,
1020 },
1021
1022 {}
1023};
1024
1025static struct snd_kcontrol_new cxt5047_hp_mixers[] = {
1026 {
1027 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1028 .name = "Capture Source",
1029 .info = conexant_mux_enum_info,
1030 .get = conexant_mux_enum_get,
1031 .put = conexant_mux_enum_put
1032 },
1033 HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
1034 HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT),
1035 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
1036 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
1037 HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
1038 HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
1039 HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
1040 {
1041 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1042 .name = "Master Playback Switch",
1043 .info = conexant_eapd_info,
1044 .get = conexant_eapd_get,
1045 .put = cxt5047_hp_master_sw_put,
1046 .private_value = 0x13,
1047 },
1048 { } /* end */
1049};
1050
1051static struct hda_verb cxt5047_init_verbs[] = {
1052 /* Line in, Mic, Built-in Mic */
1053 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1054 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
1055 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
1056 /* HP, Amp */
1057 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1058 {0x1A, AC_VERB_SET_CONNECT_SEL,0x03},
1059 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
1060 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
1061 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
1062 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
1063 /* Record selector: Front mic */
1064 {0x12, AC_VERB_SET_CONNECT_SEL,0x03},
1065 {0x19, AC_VERB_SET_AMP_GAIN_MUTE,
1066 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
1067 /* SPDIF route: PCM */
1068 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 },
1069 { } /* end */
1070};
1071
1072/* configuration for Toshiba Laptops */
1073static struct hda_verb cxt5047_toshiba_init_verbs[] = {
1074 {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
1075 /* pin sensing on HP and Mic jacks */
1076 {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
1077 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
1078 {}
1079};
1080
1081/* configuration for HP Laptops */
1082static struct hda_verb cxt5047_hp_init_verbs[] = {
1083 /* pin sensing on HP and Mic jacks */
1084 {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
1085 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
1086 {}
1087};
1088
1089/* Test configuration for debugging, modelled after the ALC260 test
1090 * configuration.
1091 */
1092#ifdef CONFIG_SND_DEBUG
1093static struct hda_input_mux cxt5047_test_capture_source = {
1094 .num_items = 5,
1095 .items = {
1096 { "MIXER", 0x0 },
1097 { "LINE1 pin", 0x1 },
1098 { "MIC1 pin", 0x2 },
1099 { "MIC2 pin", 0x3 },
1100 { "CD pin", 0x4 },
1101 },
1102};
1103
1104static struct snd_kcontrol_new cxt5047_test_mixer[] = {
1105
1106 /* Output only controls */
1107 HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x00, HDA_OUTPUT),
1108 HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x00, HDA_OUTPUT),
1109 HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x00, HDA_OUTPUT),
1110 HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x00, HDA_OUTPUT),
1111 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1112 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1113 HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1114 HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1115
1116 /* Modes for retasking pin widgets */
1117 CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT),
1118 CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT),
1119
1120 /* Loopback mixer controls */
1121 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x19, 0x02, HDA_INPUT),
1122 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x19, 0x02, HDA_INPUT),
1123 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x19, 0x03, HDA_INPUT),
1124 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x19, 0x03, HDA_INPUT),
1125 HDA_CODEC_VOLUME("LINE Playback Volume", 0x19, 0x01, HDA_INPUT),
1126 HDA_CODEC_MUTE("LINE Playback Switch", 0x19, 0x01, HDA_INPUT),
1127 HDA_CODEC_VOLUME("CD Playback Volume", 0x19, 0x04, HDA_INPUT),
1128 HDA_CODEC_MUTE("CD Playback Switch", 0x19, 0x04, HDA_INPUT),
1129
1130#if 0
1131 /* Controls for GPIO pins, assuming they exist and are configured as outputs */
1132 CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
1133 CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
1134 CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
1135 CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
1136#endif
1137 CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x18, 0x01),
1138
1139 HDA_CODEC_VOLUME("Capture Volume", 0x19, 0x0, HDA_OUTPUT),
1140 HDA_CODEC_MUTE("Capture Switch", 0x19, 0x0, HDA_OUTPUT),
1141 {
1142 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1143 .name = "Input Source",
1144 .info = conexant_mux_enum_info,
1145 .get = conexant_mux_enum_get,
1146 .put = conexant_mux_enum_put,
1147 },
1148
1149 { } /* end */
1150};
1151
1152static struct hda_verb cxt5047_test_init_verbs[] = {
1153 /* Enable all GPIOs as outputs with an initial value of 0 */
1154 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
1155 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
1156 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
1157
1158 /* Enable retasking pins as output, initially without power amp */
1159 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1160 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1161 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1162
1163 /* Disable digital (SPDIF) pins initially, but users can enable
1164 * them via a mixer switch. In the case of SPDIF-out, this initverb
1165 * payload also sets the generation to 0, output to be in "consumer"
1166 * PCM format, copyright asserted, no pre-emphasis and no validity
1167 * control.
1168 */
1169 {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0},
1170
1171 /* Ensure mic1, mic2, line1 pin widgets take input from the
1172 * OUT1 sum bus when acting as an output.
1173 */
1174 {0x1a, AC_VERB_SET_CONNECT_SEL, 0},
1175 {0x1b, AC_VERB_SET_CONNECT_SEL, 0},
1176
1177 /* Start with output sum widgets muted and their output gains at min */
1178 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1179 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1180
1181 /* Unmute retasking pin widget output buffers since the default
1182 * state appears to be output. As the pin mode is changed by the
1183 * user the pin mode control will take care of enabling the pin's
1184 * input/output buffers as needed.
1185 */
1186 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1187 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1188 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1189
1190 /* Mute capture amp left and right */
1191 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1192
1193 /* Set ADC connection select to match default mixer setting (mic1
1194 * pin)
1195 */
1196 {0x12, AC_VERB_SET_CONNECT_SEL, 0x00},
1197
1198 /* Mute all inputs to mixer widget (even unconnected ones) */
1199 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
1200 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
1201 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
1202 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
1203 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
1204 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
1205 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
1206 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
1207
1208 { }
1209};
1210#endif
1211
1212
1213/* initialize jack-sensing, too */
1214static int cxt5047_hp_init(struct hda_codec *codec)
1215{
1216 conexant_init(codec);
1217 cxt5047_hp_automute(codec);
1218 cxt5047_hp_automic(codec);
1219 return 0;
1220}
1221
1222
1223enum {
1224 CXT5047_LAPTOP, /* Laptops w/o EAPD support */
1225 CXT5047_LAPTOP_HP, /* Some HP laptops */
1226 CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */
1227#ifdef CONFIG_SND_DEBUG
1228 CXT5047_TEST,
1229#endif
1230 CXT5047_MODELS
1231};
1232
1233static const char *cxt5047_models[CXT5047_MODELS] = {
1234 [CXT5047_LAPTOP] = "laptop",
1235 [CXT5047_LAPTOP_HP] = "laptop-hp",
1236 [CXT5047_LAPTOP_EAPD] = "laptop-eapd",
1237#ifdef CONFIG_SND_DEBUG
1238 [CXT5047_TEST] = "test",
1239#endif
1240};
1241
1242static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
1243 SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP),
1244 SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP),
1245 SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
1246 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
1247 {}
1248};
1249
1250static int patch_cxt5047(struct hda_codec *codec)
1251{
1252 struct conexant_spec *spec;
1253 int board_config;
1254
1255 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1256 if (!spec)
1257 return -ENOMEM;
1258 mutex_init(&spec->amp_mutex);
1259 codec->spec = spec;
1260
1261 spec->multiout.max_channels = 2;
1262 spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids);
1263 spec->multiout.dac_nids = cxt5047_dac_nids;
1264 spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT;
1265 spec->num_adc_nids = 1;
1266 spec->adc_nids = cxt5047_adc_nids;
1267 spec->capsrc_nids = cxt5047_capsrc_nids;
1268 spec->input_mux = &cxt5047_capture_source;
1269 spec->num_mixers = 1;
1270 spec->mixers[0] = cxt5047_mixers;
1271 spec->num_init_verbs = 1;
1272 spec->init_verbs[0] = cxt5047_init_verbs;
1273 spec->spdif_route = 0;
1274 spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes),
1275 spec->channel_mode = cxt5047_modes,
1276
1277 codec->patch_ops = conexant_patch_ops;
1278 codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
1279
1280 board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
1281 cxt5047_models,
1282 cxt5047_cfg_tbl);
1283 switch (board_config) {
1284 case CXT5047_LAPTOP:
1285 break;
1286 case CXT5047_LAPTOP_HP:
1287 spec->input_mux = &cxt5047_hp_capture_source;
1288 spec->num_init_verbs = 2;
1289 spec->init_verbs[1] = cxt5047_hp_init_verbs;
1290 spec->mixers[0] = cxt5047_hp_mixers;
1291 codec->patch_ops.init = cxt5047_hp_init;
1292 break;
1293 case CXT5047_LAPTOP_EAPD:
1294 spec->num_init_verbs = 2;
1295 spec->init_verbs[1] = cxt5047_toshiba_init_verbs;
1296 break;
1297#ifdef CONFIG_SND_DEBUG
1298 case CXT5047_TEST:
1299 spec->input_mux = &cxt5047_test_capture_source;
1300 spec->mixers[0] = cxt5047_test_mixer;
1301 spec->init_verbs[0] = cxt5047_test_init_verbs;
1302#endif
1303 }
1304 return 0;
1305}
1306
1307struct hda_codec_preset snd_hda_preset_conexant[] = {
1308 { .id = 0x14f15045, .name = "CXT5045", .patch = patch_cxt5045 },
1309 { .id = 0x14f15047, .name = "CXT5047", .patch = patch_cxt5047 },
1310 {} /* terminator */
1311};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4e0c3c1b908b..145682b78071 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -32,6 +32,10 @@
32#include "hda_codec.h" 32#include "hda_codec.h"
33#include "hda_local.h" 33#include "hda_local.h"
34 34
35#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
35 39
36/* ALC880 board config type */ 40/* ALC880 board config type */
37enum { 41enum {
@@ -48,7 +52,10 @@ enum {
48 ALC880_ASUS_DIG, 52 ALC880_ASUS_DIG,
49 ALC880_ASUS_W1V, 53 ALC880_ASUS_W1V,
50 ALC880_ASUS_DIG2, 54 ALC880_ASUS_DIG2,
55 ALC880_FUJITSU,
51 ALC880_UNIWILL_DIG, 56 ALC880_UNIWILL_DIG,
57 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
52 ALC880_CLEVO, 59 ALC880_CLEVO,
53 ALC880_TCL_S700, 60 ALC880_TCL_S700,
54 ALC880_LG, 61 ALC880_LG,
@@ -77,8 +84,12 @@ enum {
77/* ALC262 models */ 84/* ALC262 models */
78enum { 85enum {
79 ALC262_BASIC, 86 ALC262_BASIC,
87 ALC262_HIPPO,
88 ALC262_HIPPO_1,
80 ALC262_FUJITSU, 89 ALC262_FUJITSU,
81 ALC262_HP_BPC, 90 ALC262_HP_BPC,
91 ALC262_HP_BPC_D7000_WL,
92 ALC262_HP_BPC_D7000_WF,
82 ALC262_BENQ_ED8, 93 ALC262_BENQ_ED8,
83 ALC262_AUTO, 94 ALC262_AUTO,
84 ALC262_MODEL_LAST /* last tag */ 95 ALC262_MODEL_LAST /* last tag */
@@ -91,16 +102,30 @@ enum {
91 ALC861_3ST_DIG, 102 ALC861_3ST_DIG,
92 ALC861_6ST_DIG, 103 ALC861_6ST_DIG,
93 ALC861_UNIWILL_M31, 104 ALC861_UNIWILL_M31,
105 ALC861_TOSHIBA,
106 ALC861_ASUS,
107 ALC861_ASUS_LAPTOP,
94 ALC861_AUTO, 108 ALC861_AUTO,
95 ALC861_MODEL_LAST, 109 ALC861_MODEL_LAST,
96}; 110};
97 111
112/* ALC861-VD models */
113enum {
114 ALC660VD_3ST,
115 ALC861VD_3ST,
116 ALC861VD_3ST_DIG,
117 ALC861VD_6ST_DIG,
118 ALC861VD_AUTO,
119 ALC861VD_MODEL_LAST,
120};
121
98/* ALC882 models */ 122/* ALC882 models */
99enum { 123enum {
100 ALC882_3ST_DIG, 124 ALC882_3ST_DIG,
101 ALC882_6ST_DIG, 125 ALC882_6ST_DIG,
102 ALC882_ARIMA, 126 ALC882_ARIMA,
103 ALC882_AUTO, 127 ALC882_AUTO,
128 ALC885_MACPRO,
104 ALC882_MODEL_LAST, 129 ALC882_MODEL_LAST,
105}; 130};
106 131
@@ -110,8 +135,12 @@ enum {
110 ALC883_3ST_6ch_DIG, 135 ALC883_3ST_6ch_DIG,
111 ALC883_3ST_6ch, 136 ALC883_3ST_6ch,
112 ALC883_6ST_DIG, 137 ALC883_6ST_DIG,
138 ALC883_TARGA_DIG,
139 ALC883_TARGA_2ch_DIG,
113 ALC888_DEMO_BOARD, 140 ALC888_DEMO_BOARD,
114 ALC883_ACER, 141 ALC883_ACER,
142 ALC883_MEDION,
143 ALC883_LAPTOP_EAPD,
115 ALC883_AUTO, 144 ALC883_AUTO,
116 ALC883_MODEL_LAST, 145 ALC883_MODEL_LAST,
117}; 146};
@@ -1015,6 +1044,60 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1015 { } /* end */ 1044 { } /* end */
1016}; 1045};
1017 1046
1047/* Uniwill */
1048static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
1049 HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1050 HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
1051 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1052 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
1053 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1054 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1055 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1056 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1057 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1058 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1059 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1060 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1061 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1062 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1063 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1064 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1065 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1066 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1067 {
1068 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1069 .name = "Channel Mode",
1070 .info = alc_ch_mode_info,
1071 .get = alc_ch_mode_get,
1072 .put = alc_ch_mode_put,
1073 },
1074 { } /* end */
1075};
1076
1077static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1078 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1079 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1080 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1081 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1082 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1083 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1084 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1085 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1086 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1087 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1088 { } /* end */
1089};
1090
1091static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
1092 HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1093 HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
1094 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1095 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
1096 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1097 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1098 { } /* end */
1099};
1100
1018/* 1101/*
1019 * build control elements 1102 * build control elements
1020 */ 1103 */
@@ -1248,6 +1331,159 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1248 { } 1331 { }
1249}; 1332};
1250 1333
1334/*
1335 * Uniwill pin configuration:
1336 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1337 * line = 0x1a
1338 */
1339static struct hda_verb alc880_uniwill_init_verbs[] = {
1340 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1341
1342 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1343 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1344 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1345 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1346 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1347 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1348 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1349 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1350 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1351 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1352 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1353 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1354 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1355 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1356
1357 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1358 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1359 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1360 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1361 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1362 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1363 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1364 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1365 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1366
1367 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1368 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1369
1370 { }
1371};
1372
1373/*
1374* Uniwill P53
1375* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
1376 */
1377static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1378 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1379
1380 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1381 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1382 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1383 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1384 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1385 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1386 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1387 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1388 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1389 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1390 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1391 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1392
1393 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1394 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1395 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1396 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1397 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1398 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1399
1400 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1401 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1402
1403 { }
1404};
1405
1406static struct hda_verb alc880_beep_init_verbs[] = {
1407 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1408 { }
1409};
1410
1411/* toggle speaker-output according to the hp-jack state */
1412static void alc880_uniwill_automute(struct hda_codec *codec)
1413{
1414 unsigned int present;
1415
1416 present = snd_hda_codec_read(codec, 0x14, 0,
1417 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1418 snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
1419 0x80, present ? 0x80 : 0);
1420 snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
1421 0x80, present ? 0x80 : 0);
1422 snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0,
1423 0x80, present ? 0x80 : 0);
1424 snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0,
1425 0x80, present ? 0x80 : 0);
1426
1427 present = snd_hda_codec_read(codec, 0x18, 0,
1428 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1429 snd_hda_codec_write(codec, 0x0b, 0, AC_VERB_SET_AMP_GAIN_MUTE,
1430 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
1431}
1432
1433static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1434 unsigned int res)
1435{
1436 /* Looks like the unsol event is incompatible with the standard
1437 * definition. 4bit tag is placed at 28 bit!
1438 */
1439 if ((res >> 28) == ALC880_HP_EVENT ||
1440 (res >> 28) == ALC880_MIC_EVENT)
1441 alc880_uniwill_automute(codec);
1442}
1443
1444static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1445{
1446 unsigned int present;
1447
1448 present = snd_hda_codec_read(codec, 0x14, 0,
1449 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1450
1451 snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0,
1452 0x80, present ? 0x80 : 0);
1453 snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0,
1454 0x80, present ? 0x80 : 0);
1455}
1456
1457static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1458{
1459 unsigned int present;
1460
1461 present = snd_hda_codec_read(codec, 0x21, 0,
1462 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f;
1463
1464 snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0,
1465 0x7f, present);
1466 snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0,
1467 0x7f, present);
1468
1469 snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0,
1470 0x7f, present);
1471 snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0,
1472 0x7f, present);
1473
1474}
1475static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1476 unsigned int res)
1477{
1478 /* Looks like the unsol event is incompatible with the standard
1479 * definition. 4bit tag is placed at 28 bit!
1480 */
1481 if ((res >> 28) == ALC880_HP_EVENT)
1482 alc880_uniwill_p53_hp_automute(codec);
1483 if ((res >> 28) == ALC880_DCVOL_EVENT)
1484 alc880_uniwill_p53_dcvol_automute(codec);
1485}
1486
1251/* FIXME! */ 1487/* FIXME! */
1252/* 1488/*
1253 * F1734 pin configuration: 1489 * F1734 pin configuration:
@@ -2125,159 +2361,112 @@ static struct hda_verb alc880_test_init_verbs[] = {
2125/* 2361/*
2126 */ 2362 */
2127 2363
2128static struct hda_board_config alc880_cfg_tbl[] = { 2364static const char *alc880_models[ALC880_MODEL_LAST] = {
2129 /* Back 3 jack, front 2 jack */ 2365 [ALC880_3ST] = "3stack",
2130 { .modelname = "3stack", .config = ALC880_3ST }, 2366 [ALC880_TCL_S700] = "tcl",
2131 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST }, 2367 [ALC880_3ST_DIG] = "3stack-digout",
2132 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST }, 2368 [ALC880_CLEVO] = "clevo",
2133 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST }, 2369 [ALC880_5ST] = "5stack",
2134 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST }, 2370 [ALC880_5ST_DIG] = "5stack-digout",
2135 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST }, 2371 [ALC880_W810] = "w810",
2136 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST }, 2372 [ALC880_Z71V] = "z71v",
2137 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST }, 2373 [ALC880_6ST] = "6stack",
2138 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST }, 2374 [ALC880_6ST_DIG] = "6stack-digout",
2139 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST }, 2375 [ALC880_ASUS] = "asus",
2140 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST }, 2376 [ALC880_ASUS_W1V] = "asus-w1v",
2141 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST }, 2377 [ALC880_ASUS_DIG] = "asus-dig",
2142 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST }, 2378 [ALC880_ASUS_DIG2] = "asus-dig2",
2143 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST }, 2379 [ALC880_UNIWILL_DIG] = "uniwill",
2144 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST }, 2380 [ALC880_UNIWILL_P53] = "uniwill-p53",
2145 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST }, 2381 [ALC880_FUJITSU] = "fujitsu",
2146 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, 2382 [ALC880_F1734] = "F1734",
2147 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, 2383 [ALC880_LG] = "lg",
2148 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, 2384 [ALC880_LG_LW] = "lg-lw",
2149 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST },
2150 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST },
2151 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
2152 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST },
2153 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
2154 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
2155 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
2156 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST },
2157 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST },
2158 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST },
2159 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST },
2160 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST },
2161 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST },
2162 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST },
2163 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST },
2164 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
2165 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
2166 /* TCL S700 */
2167 { .modelname = "tcl", .config = ALC880_TCL_S700 },
2168 { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 },
2169
2170 /* Back 3 jack, front 2 jack (Internal add Aux-In) */
2171 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST },
2172 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST },
2173 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST },
2174
2175 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
2176 { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
2177 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
2178 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
2179
2180 /* Clevo laptops */
2181 { .modelname = "clevo", .config = ALC880_CLEVO },
2182 { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520,
2183 .config = ALC880_CLEVO }, /* Clevo m520G NB */
2184 { .pci_subvendor = 0x1558, .pci_subdevice = 0x0660,
2185 .config = ALC880_CLEVO }, /* Clevo m665n */
2186
2187 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
2188 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
2189 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG },
2190 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG },
2191
2192 /* Back 5 jack, front 2 jack */
2193 { .modelname = "5stack", .config = ALC880_5ST },
2194 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST },
2195 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST },
2196 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST },
2197 { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST },
2198 { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST },
2199
2200 /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
2201 { .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
2202 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG },
2203 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG },
2204 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG },
2205 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG },
2206 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG },
2207 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG },
2208 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
2209 { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
2210 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
2211 { .pci_subvendor = 0xa0a0, .pci_subdevice = 0x0560,
2212 .config = ALC880_5ST_DIG }, /* Aopen i915GMm-HFS */
2213 /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
2214 { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
2215 /* note subvendor = 0 below */
2216 /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */
2217
2218 { .modelname = "w810", .config = ALC880_W810 },
2219 { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
2220
2221 { .modelname = "z71v", .config = ALC880_Z71V },
2222 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
2223
2224 { .modelname = "6stack", .config = ALC880_6ST },
2225 { .pci_subvendor = 0x1043, .pci_subdevice = 0x8196, .config = ALC880_6ST }, /* ASUS P5GD1-HVM */
2226 { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST },
2227 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */
2228 { .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST }, /* Gigabyte K8N51 */
2229
2230 { .modelname = "6stack-digout", .config = ALC880_6ST_DIG },
2231 { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
2232 { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
2233 { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
2234 { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG },
2235 { .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG },
2236 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG },
2237 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG },
2238 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG },
2239 { .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */
2240 { .pci_subvendor = 0x1509, .pci_subdevice = 0x925d, .config = ALC880_6ST_DIG }, /* FIC P4M-915GD1 */
2241 { .pci_subvendor = 0x1695, .pci_subdevice = 0x4012, .config = ALC880_5ST_DIG }, /* Epox EP-5LDA+ GLi */
2242
2243 { .modelname = "asus", .config = ALC880_ASUS },
2244 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG },
2245 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG },
2246 { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG },
2247 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
2248 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
2249 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
2250 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */
2251 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
2252 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
2253 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
2254 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
2255 { .modelname = "asus-w1v", .config = ALC880_ASUS_W1V },
2256 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
2257 { .modelname = "asus-dig", .config = ALC880_ASUS_DIG },
2258 { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */
2259 { .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 },
2260 { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
2261
2262 { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
2263 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG },
2264
2265 { .modelname = "F1734", .config = ALC880_F1734 },
2266 { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
2267 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 },
2268
2269 { .modelname = "lg", .config = ALC880_LG },
2270 { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
2271 { .pci_subvendor = 0x1854, .pci_subdevice = 0x0068, .config = ALC880_LG },
2272
2273 { .modelname = "lg-lw", .config = ALC880_LG_LW },
2274 { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
2275 { .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW },
2276
2277#ifdef CONFIG_SND_DEBUG 2385#ifdef CONFIG_SND_DEBUG
2278 { .modelname = "test", .config = ALC880_TEST }, 2386 [ALC880_TEST] = "test",
2279#endif 2387#endif
2280 { .modelname = "auto", .config = ALC880_AUTO }, 2388 [ALC880_AUTO] = "auto",
2389};
2390
2391static struct snd_pci_quirk alc880_cfg_tbl[] = {
2392 /* Broken BIOS configuration */
2393 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG),
2394 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
2395
2396 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
2397 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
2398 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
2399 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
2400 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
2401 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
2402 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
2403 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
2404 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
2405
2406 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
2407 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
2408
2409 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
2410 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
2411 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
2412 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
2413 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
2414 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
2415 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
2416 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
2417 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
2418 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
2419 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
2420 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
2421 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
2422 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
2423 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS),
2424
2425 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
2426 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
2427 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
2428 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
2429 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
2430 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
2431 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
2432 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
2433 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
2434 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
2435 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
2436 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
2437 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
2438 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
2439 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
2440 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
2441 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
2442 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
2443
2444 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
2445 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
2446 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
2447 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
2448
2449 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
2450 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
2451 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
2452 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
2453
2454 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
2455 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
2456 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
2457 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
2458
2459 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
2460 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
2461 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
2462 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
2463 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
2464 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
2465 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
2466 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
2467 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
2468 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
2469 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST),
2281 2470
2282 {} 2471 {}
2283}; 2472};
@@ -2438,7 +2627,8 @@ static struct alc_config_preset alc880_presets[] = {
2438 }, 2627 },
2439 [ALC880_UNIWILL_DIG] = { 2628 [ALC880_UNIWILL_DIG] = {
2440 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer }, 2629 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
2441 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs }, 2630 .init_verbs = { alc880_volume_init_verbs,
2631 alc880_pin_asus_init_verbs },
2442 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), 2632 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2443 .dac_nids = alc880_asus_dac_nids, 2633 .dac_nids = alc880_asus_dac_nids,
2444 .dig_out_nid = ALC880_DIGOUT_NID, 2634 .dig_out_nid = ALC880_DIGOUT_NID,
@@ -2447,6 +2637,46 @@ static struct alc_config_preset alc880_presets[] = {
2447 .need_dac_fix = 1, 2637 .need_dac_fix = 1,
2448 .input_mux = &alc880_capture_source, 2638 .input_mux = &alc880_capture_source,
2449 }, 2639 },
2640 [ALC880_UNIWILL] = {
2641 .mixers = { alc880_uniwill_mixer },
2642 .init_verbs = { alc880_volume_init_verbs,
2643 alc880_uniwill_init_verbs },
2644 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2645 .dac_nids = alc880_asus_dac_nids,
2646 .dig_out_nid = ALC880_DIGOUT_NID,
2647 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2648 .channel_mode = alc880_threestack_modes,
2649 .need_dac_fix = 1,
2650 .input_mux = &alc880_capture_source,
2651 .unsol_event = alc880_uniwill_unsol_event,
2652 .init_hook = alc880_uniwill_automute,
2653 },
2654 [ALC880_UNIWILL_P53] = {
2655 .mixers = { alc880_uniwill_p53_mixer },
2656 .init_verbs = { alc880_volume_init_verbs,
2657 alc880_uniwill_p53_init_verbs },
2658 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2659 .dac_nids = alc880_asus_dac_nids,
2660 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
2661 .channel_mode = alc880_threestack_modes,
2662 .input_mux = &alc880_capture_source,
2663 .unsol_event = alc880_uniwill_p53_unsol_event,
2664 .init_hook = alc880_uniwill_p53_hp_automute,
2665 },
2666 [ALC880_FUJITSU] = {
2667 .mixers = { alc880_fujitsu_mixer,
2668 alc880_pcbeep_mixer, },
2669 .init_verbs = { alc880_volume_init_verbs,
2670 alc880_uniwill_p53_init_verbs,
2671 alc880_beep_init_verbs },
2672 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2673 .dac_nids = alc880_dac_nids,
2674 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2675 .channel_mode = alc880_2_jack_modes,
2676 .input_mux = &alc880_capture_source,
2677 .unsol_event = alc880_uniwill_p53_unsol_event,
2678 .init_hook = alc880_uniwill_p53_hp_automute,
2679 },
2450 [ALC880_CLEVO] = { 2680 [ALC880_CLEVO] = {
2451 .mixers = { alc880_three_stack_mixer }, 2681 .mixers = { alc880_three_stack_mixer },
2452 .init_verbs = { alc880_volume_init_verbs, 2682 .init_verbs = { alc880_volume_init_verbs,
@@ -2841,8 +3071,10 @@ static int patch_alc880(struct hda_codec *codec)
2841 3071
2842 codec->spec = spec; 3072 codec->spec = spec;
2843 3073
2844 board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); 3074 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
2845 if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { 3075 alc880_models,
3076 alc880_cfg_tbl);
3077 if (board_config < 0) {
2846 printk(KERN_INFO "hda_codec: Unknown model for ALC880, " 3078 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
2847 "trying auto-probe from BIOS...\n"); 3079 "trying auto-probe from BIOS...\n");
2848 board_config = ALC880_AUTO; 3080 board_config = ALC880_AUTO;
@@ -3090,11 +3322,20 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
3090 * and the output jack. If this turns out to be the case for all such 3322 * and the output jack. If this turns out to be the case for all such
3091 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT 3323 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
3092 * to ALC_PIN_DIR_INOUT_NOMICBIAS. 3324 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
3325 *
3326 * The C20x Tablet series have a mono internal speaker which is controlled
3327 * via the chip's Mono sum widget and pin complex, so include the necessary
3328 * controls for such models. On models without a "mono speaker" the control
3329 * won't do anything.
3093 */ 3330 */
3094static struct snd_kcontrol_new alc260_acer_mixer[] = { 3331static struct snd_kcontrol_new alc260_acer_mixer[] = {
3095 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), 3332 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3096 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), 3333 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
3097 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), 3334 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
3335 HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0,
3336 HDA_OUTPUT),
3337 HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2,
3338 HDA_INPUT),
3098 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), 3339 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3099 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), 3340 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3100 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), 3341 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -3409,11 +3650,11 @@ static struct hda_verb alc260_acer_init_verbs[] = {
3409 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, 3650 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
3410 /* Line In jack is connected to Line1 pin */ 3651 /* Line In jack is connected to Line1 pin */
3411 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 3652 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3653 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
3654 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3412 /* Ensure all other unused pins are disabled and muted. */ 3655 /* Ensure all other unused pins are disabled and muted. */
3413 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 3656 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
3414 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3657 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3415 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
3416 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3417 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 3658 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
3418 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 3659 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3419 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 3660 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -3441,6 +3682,8 @@ static struct hda_verb alc260_acer_init_verbs[] = {
3441 3682
3442 /* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */ 3683 /* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */
3443 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 3684 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3685 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
3686 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3444 /* Unmute Mic1 and Line1 pin widget input buffers since they start as 3687 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
3445 * inputs. If the pin mode is changed by the user the pin mode control 3688 * inputs. If the pin mode is changed by the user the pin mode control
3446 * will take care of enabling the pin's input/output buffers as needed. 3689 * will take care of enabling the pin's input/output buffers as needed.
@@ -3928,33 +4171,33 @@ static void alc260_auto_init(struct hda_codec *codec)
3928/* 4171/*
3929 * ALC260 configurations 4172 * ALC260 configurations
3930 */ 4173 */
3931static struct hda_board_config alc260_cfg_tbl[] = { 4174static const char *alc260_models[ALC260_MODEL_LAST] = {
3932 { .modelname = "basic", .config = ALC260_BASIC }, 4175 [ALC260_BASIC] = "basic",
3933 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb, 4176 [ALC260_HP] = "hp",
3934 .config = ALC260_BASIC }, /* Sony VAIO */ 4177 [ALC260_HP_3013] = "hp-3013",
3935 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cc, 4178 [ALC260_FUJITSU_S702X] = "fujitsu",
3936 .config = ALC260_BASIC }, /* Sony VAIO VGN-S3HP */ 4179 [ALC260_ACER] = "acer",
3937 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cd,
3938 .config = ALC260_BASIC }, /* Sony VAIO */
3939 { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
3940 .config = ALC260_BASIC }, /* CTL Travel Master U553W */
3941 { .modelname = "hp", .config = ALC260_HP },
3942 { .modelname = "hp-3013", .config = ALC260_HP_3013 },
3943 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 },
3944 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
3945 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 },
3946 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
3947 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP },
3948 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP },
3949 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP },
3950 { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X },
3951 { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X },
3952 { .modelname = "acer", .config = ALC260_ACER },
3953 { .pci_subvendor = 0x1025, .pci_subdevice = 0x008f, .config = ALC260_ACER },
3954#ifdef CONFIG_SND_DEBUG 4180#ifdef CONFIG_SND_DEBUG
3955 { .modelname = "test", .config = ALC260_TEST }, 4181 [ALC260_TEST] = "test",
3956#endif 4182#endif
3957 { .modelname = "auto", .config = ALC260_AUTO }, 4183 [ALC260_AUTO] = "auto",
4184};
4185
4186static struct snd_pci_quirk alc260_cfg_tbl[] = {
4187 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
4188 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
4189 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
4190 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
4191 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
4192 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
4193 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
4194 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
4195 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
4196 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
4197 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
4198 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
4199 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
4200 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
3958 {} 4201 {}
3959}; 4202};
3960 4203
@@ -4053,8 +4296,10 @@ static int patch_alc260(struct hda_codec *codec)
4053 4296
4054 codec->spec = spec; 4297 codec->spec = spec;
4055 4298
4056 board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); 4299 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
4057 if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { 4300 alc260_models,
4301 alc260_cfg_tbl);
4302 if (board_config < 0) {
4058 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, " 4303 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
4059 "trying auto-probe from BIOS...\n"); 4304 "trying auto-probe from BIOS...\n");
4060 board_config = ALC260_AUTO; 4305 board_config = ALC260_AUTO;
@@ -4207,8 +4452,10 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
4207 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 4452 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4208 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 4453 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
4209 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 4454 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4455 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
4210 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 4456 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4211 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 4457 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
4458 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
4212 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 4459 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
4213 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 4460 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
4214 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 4461 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4313,6 +4560,100 @@ static struct hda_verb alc882_eapd_verbs[] = {
4313 { } 4560 { }
4314}; 4561};
4315 4562
4563/* Mac Pro test */
4564static struct snd_kcontrol_new alc882_macpro_mixer[] = {
4565 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4566 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4567 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
4568 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
4569 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
4570 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
4571 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
4572 { } /* end */
4573};
4574
4575static struct hda_verb alc882_macpro_init_verbs[] = {
4576 /* Front mixer: unmute input/output amp left and right (volume = 0) */
4577 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4578 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4579 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4580 /* Front Pin: output 0 (0x0c) */
4581 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4582 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4583 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
4584 /* Front Mic pin: input vref at 80% */
4585 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4586 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4587 /* Speaker: output */
4588 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4589 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4590 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
4591 /* Headphone output (output 0 - 0x0c) */
4592 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4593 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4594 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
4595
4596 /* FIXME: use matrix-type input source selection */
4597 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
4598 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
4599 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4600 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4601 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4602 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4603 /* Input mixer2 */
4604 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4605 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4606 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4607 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4608 /* Input mixer3 */
4609 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4610 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4611 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4612 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4613 /* ADC1: mute amp left and right */
4614 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4615 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
4616 /* ADC2: mute amp left and right */
4617 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4618 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
4619 /* ADC3: mute amp left and right */
4620 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4621 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
4622
4623 { }
4624};
4625static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
4626{
4627 unsigned int gpiostate, gpiomask, gpiodir;
4628
4629 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
4630 AC_VERB_GET_GPIO_DATA, 0);
4631
4632 if (!muted)
4633 gpiostate |= (1 << pin);
4634 else
4635 gpiostate &= ~(1 << pin);
4636
4637 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
4638 AC_VERB_GET_GPIO_MASK, 0);
4639 gpiomask |= (1 << pin);
4640
4641 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
4642 AC_VERB_GET_GPIO_DIRECTION, 0);
4643 gpiodir |= (1 << pin);
4644
4645
4646 snd_hda_codec_write(codec, codec->afg, 0,
4647 AC_VERB_SET_GPIO_MASK, gpiomask);
4648 snd_hda_codec_write(codec, codec->afg, 0,
4649 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
4650
4651 msleep(1);
4652
4653 snd_hda_codec_write(codec, codec->afg, 0,
4654 AC_VERB_SET_GPIO_DATA, gpiostate);
4655}
4656
4316/* 4657/*
4317 * generic initialization of ADC, input mixers and output mixers 4658 * generic initialization of ADC, input mixers and output mixers
4318 */ 4659 */
@@ -4435,19 +4776,20 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = {
4435/* 4776/*
4436 * configuration and preset 4777 * configuration and preset
4437 */ 4778 */
4438static struct hda_board_config alc882_cfg_tbl[] = { 4779static const char *alc882_models[ALC882_MODEL_LAST] = {
4439 { .modelname = "3stack-dig", .config = ALC882_3ST_DIG }, 4780 [ALC882_3ST_DIG] = "3stack-dig",
4440 { .modelname = "6stack-dig", .config = ALC882_6ST_DIG }, 4781 [ALC882_6ST_DIG] = "6stack-dig",
4441 { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, 4782 [ALC882_ARIMA] = "arima",
4442 .config = ALC882_6ST_DIG }, /* MSI */ 4783 [ALC885_MACPRO] = "macpro",
4443 { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, 4784 [ALC882_AUTO] = "auto",
4444 .config = ALC882_6ST_DIG }, /* Foxconn */ 4785};
4445 { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, 4786
4446 .config = ALC882_6ST_DIG }, /* ECS to Intel*/ 4787static struct snd_pci_quirk alc882_cfg_tbl[] = {
4447 { .modelname = "arima", .config = ALC882_ARIMA }, 4788 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
4448 { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, 4789 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
4449 .config = ALC882_ARIMA }, /* Arima W820Di1 */ 4790 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
4450 { .modelname = "auto", .config = ALC882_AUTO }, 4791 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
4792 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
4451 {} 4793 {}
4452}; 4794};
4453 4795
@@ -4484,6 +4826,17 @@ static struct alc_config_preset alc882_presets[] = {
4484 .channel_mode = alc882_sixstack_modes, 4826 .channel_mode = alc882_sixstack_modes,
4485 .input_mux = &alc882_capture_source, 4827 .input_mux = &alc882_capture_source,
4486 }, 4828 },
4829 [ALC885_MACPRO] = {
4830 .mixers = { alc882_macpro_mixer },
4831 .init_verbs = { alc882_macpro_init_verbs },
4832 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
4833 .dac_nids = alc882_dac_nids,
4834 .dig_out_nid = ALC882_DIGOUT_NID,
4835 .dig_in_nid = ALC882_DIGIN_NID,
4836 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
4837 .channel_mode = alc882_ch_modes,
4838 .input_mux = &alc882_capture_source,
4839 },
4487}; 4840};
4488 4841
4489 4842
@@ -4584,7 +4937,9 @@ static int patch_alc882(struct hda_codec *codec)
4584 4937
4585 codec->spec = spec; 4938 codec->spec = spec;
4586 4939
4587 board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl); 4940 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
4941 alc882_models,
4942 alc882_cfg_tbl);
4588 4943
4589 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { 4944 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
4590 printk(KERN_INFO "hda_codec: Unknown model for ALC882, " 4945 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
@@ -4609,6 +4964,11 @@ static int patch_alc882(struct hda_codec *codec)
4609 if (board_config != ALC882_AUTO) 4964 if (board_config != ALC882_AUTO)
4610 setup_preset(spec, &alc882_presets[board_config]); 4965 setup_preset(spec, &alc882_presets[board_config]);
4611 4966
4967 if (board_config == ALC885_MACPRO) {
4968 alc882_gpio_mute(codec, 0, 0);
4969 alc882_gpio_mute(codec, 1, 0);
4970 }
4971
4612 spec->stream_name_analog = "ALC882 Analog"; 4972 spec->stream_name_analog = "ALC882 Analog";
4613 spec->stream_analog_playback = &alc882_pcm_analog_playback; 4973 spec->stream_analog_playback = &alc882_pcm_analog_playback;
4614 spec->stream_analog_capture = &alc882_pcm_analog_capture; 4974 spec->stream_analog_capture = &alc882_pcm_analog_capture;
@@ -4767,6 +5127,13 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = {
4767 { 8, alc883_sixstack_ch8_init }, 5127 { 8, alc883_sixstack_ch8_init },
4768}; 5128};
4769 5129
5130static struct hda_verb alc883_medion_eapd_verbs[] = {
5131 /* eanable EAPD on medion laptop */
5132 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
5133 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
5134 { }
5135};
5136
4770/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 5137/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
4771 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b 5138 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
4772 */ 5139 */
@@ -4788,8 +5155,10 @@ static struct snd_kcontrol_new alc883_base_mixer[] = {
4788 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 5155 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4789 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 5156 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
4790 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 5157 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5158 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
4791 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 5159 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4792 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 5160 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5161 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
4793 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 5162 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
4794 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 5163 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
4795 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 5164 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4818,8 +5187,10 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
4818 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 5187 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4819 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 5188 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
4820 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 5189 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5190 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
4821 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 5191 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4822 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 5192 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5193 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
4823 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 5194 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
4824 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 5195 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
4825 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 5196 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4854,8 +5225,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
4854 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 5225 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4855 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 5226 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
4856 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 5227 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5228 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
4857 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 5229 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4858 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 5230 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5231 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
4859 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 5232 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
4860 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 5233 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
4861 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 5234 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4875,6 +5248,101 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
4875 { } /* end */ 5248 { } /* end */
4876}; 5249};
4877 5250
5251static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
5252 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5253 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5254 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
5255 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5256 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5257 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
5258 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
5259 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
5260 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5261 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5262 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5263 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5264 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5265 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5266 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5267 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5268 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5269 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
5270 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5271 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5272 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5273 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5274 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5275
5276 {
5277 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5278 /* .name = "Capture Source", */
5279 .name = "Input Source",
5280 .count = 1,
5281 .info = alc883_mux_enum_info,
5282 .get = alc883_mux_enum_get,
5283 .put = alc883_mux_enum_put,
5284 },
5285 { } /* end */
5286};
5287
5288static struct snd_kcontrol_new alc883_tagra_mixer[] = {
5289 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5290 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5291 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5292 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
5293 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
5294 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5295 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
5296 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5297 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
5298 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5299 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5300 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5301 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5302 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5303 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5304 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5305 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5306 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5307 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
5308 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
5309 {
5310 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5311 /* .name = "Capture Source", */
5312 .name = "Input Source",
5313 .count = 2,
5314 .info = alc883_mux_enum_info,
5315 .get = alc883_mux_enum_get,
5316 .put = alc883_mux_enum_put,
5317 },
5318 { } /* end */
5319};
5320
5321static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
5322 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5323 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5324 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5325 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5326 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5327 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5328 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5329 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5330 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5331 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5332 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
5333 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
5334 {
5335 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5336 /* .name = "Capture Source", */
5337 .name = "Input Source",
5338 .count = 2,
5339 .info = alc883_mux_enum_info,
5340 .get = alc883_mux_enum_get,
5341 .put = alc883_mux_enum_put,
5342 },
5343 { } /* end */
5344};
5345
4878static struct snd_kcontrol_new alc883_chmode_mixer[] = { 5346static struct snd_kcontrol_new alc883_chmode_mixer[] = {
4879 { 5347 {
4880 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5348 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -4963,6 +5431,45 @@ static struct hda_verb alc883_init_verbs[] = {
4963 { } 5431 { }
4964}; 5432};
4965 5433
5434static struct hda_verb alc883_tagra_verbs[] = {
5435 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5436 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5437
5438 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5439 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5440
5441 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5442 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5443 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5444
5445 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5446 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5447 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
5448 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
5449
5450 { } /* end */
5451};
5452
5453/* toggle speaker-output according to the hp-jack state */
5454static void alc883_tagra_automute(struct hda_codec *codec)
5455{
5456 unsigned int present;
5457
5458 present = snd_hda_codec_read(codec, 0x14, 0,
5459 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5460 snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
5461 0x80, present ? 0x80 : 0);
5462 snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
5463 0x80, present ? 0x80 : 0);
5464 snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3);
5465}
5466
5467static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
5468{
5469 if ((res >> 26) == ALC880_HP_EVENT)
5470 alc883_tagra_automute(codec);
5471}
5472
4966/* 5473/*
4967 * generic initialization of ADC, input mixers and output mixers 5474 * generic initialization of ADC, input mixers and output mixers
4968 */ 5475 */
@@ -5057,32 +5564,42 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = {
5057/* 5564/*
5058 * configuration and preset 5565 * configuration and preset
5059 */ 5566 */
5060static struct hda_board_config alc883_cfg_tbl[] = { 5567static const char *alc883_models[ALC883_MODEL_LAST] = {
5061 { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG }, 5568 [ALC883_3ST_2ch_DIG] = "3stack-dig",
5062 { .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG }, 5569 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
5063 { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, 5570 [ALC883_3ST_6ch] = "3stack-6ch",
5064 .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/ 5571 [ALC883_6ST_DIG] = "6stack-dig",
5065 { .modelname = "3stack-6ch", .config = ALC883_3ST_6ch }, 5572 [ALC883_TARGA_DIG] = "targa-dig",
5066 { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d, 5573 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
5067 .config = ALC883_3ST_6ch }, 5574 [ALC888_DEMO_BOARD] = "6stack-dig-demo",
5068 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601, 5575 [ALC883_ACER] = "acer",
5069 .config = ALC883_3ST_6ch }, /* D102GGC */ 5576 [ALC883_MEDION] = "medion",
5070 { .modelname = "6stack-dig", .config = ALC883_6ST_DIG }, 5577 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
5071 { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, 5578 [ALC883_AUTO] = "auto",
5072 .config = ALC883_6ST_DIG }, /* MSI */ 5579};
5073 { .pci_subvendor = 0x1462, .pci_subdevice = 0x7280, 5580
5074 .config = ALC883_6ST_DIG }, /* MSI K9A Platinum (MS-7280) */ 5581static struct snd_pci_quirk alc883_cfg_tbl[] = {
5075 { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, 5582 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
5076 .config = ALC883_6ST_DIG }, /* Foxconn */ 5583 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
5077 { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD }, 5584 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
5078 { .modelname = "acer", .config = ALC883_ACER }, 5585 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
5079 { .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/, 5586 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
5080 .config = ALC883_ACER }, 5587 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
5081 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0102, 5588 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
5082 .config = ALC883_ACER }, 5589 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
5083 { .pci_subvendor = 0x1025, .pci_subdevice = 0x009f, 5590 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
5084 .config = ALC883_ACER }, 5591 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
5085 { .modelname = "auto", .config = ALC883_AUTO }, 5592 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
5593 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
5594 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
5595 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
5596 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
5597 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
5598 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
5599 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER),
5600 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
5601 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
5602 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
5086 {} 5603 {}
5087}; 5604};
5088 5605
@@ -5139,6 +5656,35 @@ static struct alc_config_preset alc883_presets[] = {
5139 .channel_mode = alc883_sixstack_modes, 5656 .channel_mode = alc883_sixstack_modes,
5140 .input_mux = &alc883_capture_source, 5657 .input_mux = &alc883_capture_source,
5141 }, 5658 },
5659 [ALC883_TARGA_DIG] = {
5660 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
5661 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
5662 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
5663 .dac_nids = alc883_dac_nids,
5664 .dig_out_nid = ALC883_DIGOUT_NID,
5665 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
5666 .adc_nids = alc883_adc_nids,
5667 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
5668 .channel_mode = alc883_3ST_6ch_modes,
5669 .need_dac_fix = 1,
5670 .input_mux = &alc883_capture_source,
5671 .unsol_event = alc883_tagra_unsol_event,
5672 .init_hook = alc883_tagra_automute,
5673 },
5674 [ALC883_TARGA_2ch_DIG] = {
5675 .mixers = { alc883_tagra_2ch_mixer},
5676 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
5677 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
5678 .dac_nids = alc883_dac_nids,
5679 .dig_out_nid = ALC883_DIGOUT_NID,
5680 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
5681 .adc_nids = alc883_adc_nids,
5682 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
5683 .channel_mode = alc883_3ST_2ch_modes,
5684 .input_mux = &alc883_capture_source,
5685 .unsol_event = alc883_tagra_unsol_event,
5686 .init_hook = alc883_tagra_automute,
5687 },
5142 [ALC888_DEMO_BOARD] = { 5688 [ALC888_DEMO_BOARD] = {
5143 .mixers = { alc883_base_mixer, alc883_chmode_mixer }, 5689 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
5144 .init_verbs = { alc883_init_verbs }, 5690 .init_verbs = { alc883_init_verbs },
@@ -5169,6 +5715,31 @@ static struct alc_config_preset alc883_presets[] = {
5169 .channel_mode = alc883_3ST_2ch_modes, 5715 .channel_mode = alc883_3ST_2ch_modes,
5170 .input_mux = &alc883_capture_source, 5716 .input_mux = &alc883_capture_source,
5171 }, 5717 },
5718 [ALC883_MEDION] = {
5719 .mixers = { alc883_fivestack_mixer,
5720 alc883_chmode_mixer },
5721 .init_verbs = { alc883_init_verbs,
5722 alc883_medion_eapd_verbs },
5723 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
5724 .dac_nids = alc883_dac_nids,
5725 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
5726 .adc_nids = alc883_adc_nids,
5727 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
5728 .channel_mode = alc883_sixstack_modes,
5729 .input_mux = &alc883_capture_source,
5730 },
5731 [ALC883_LAPTOP_EAPD] = {
5732 .mixers = { alc883_base_mixer,
5733 alc883_chmode_mixer },
5734 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
5735 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
5736 .dac_nids = alc883_dac_nids,
5737 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
5738 .adc_nids = alc883_adc_nids,
5739 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
5740 .channel_mode = alc883_3ST_2ch_modes,
5741 .input_mux = &alc883_capture_source,
5742 },
5172}; 5743};
5173 5744
5174 5745
@@ -5277,8 +5848,10 @@ static int patch_alc883(struct hda_codec *codec)
5277 5848
5278 codec->spec = spec; 5849 codec->spec = spec;
5279 5850
5280 board_config = snd_hda_check_board_config(codec, alc883_cfg_tbl); 5851 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
5281 if (board_config < 0 || board_config >= ALC883_MODEL_LAST) { 5852 alc883_models,
5853 alc883_cfg_tbl);
5854 if (board_config < 0) {
5282 printk(KERN_INFO "hda_codec: Unknown model for ALC883, " 5855 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
5283 "trying auto-probe from BIOS...\n"); 5856 "trying auto-probe from BIOS...\n");
5284 board_config = ALC883_AUTO; 5857 board_config = ALC883_AUTO;
@@ -5355,6 +5928,24 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
5355 { } /* end */ 5928 { } /* end */
5356}; 5929};
5357 5930
5931static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
5932 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5933 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5934 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5935 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5936 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5937 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5938 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5939 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5940 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
5941 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
5942 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
5943 HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
5944 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
5945 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5946 { } /* end */
5947};
5948
5358static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { 5949static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
5359 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 5950 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5360 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), 5951 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -5377,6 +5968,30 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
5377 { } /* end */ 5968 { } /* end */
5378}; 5969};
5379 5970
5971static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
5972 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5973 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5974 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
5975 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5976 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
5977 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
5978 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
5979 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
5980 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5981 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5982 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5983 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5984 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
5985 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
5986 { } /* end */
5987};
5988
5989static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
5990 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5991 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5992 { } /* end */
5993};
5994
5380#define alc262_capture_mixer alc882_capture_mixer 5995#define alc262_capture_mixer alc882_capture_mixer
5381#define alc262_capture_alt_mixer alc882_capture_alt_mixer 5996#define alc262_capture_alt_mixer alc882_capture_alt_mixer
5382 5997
@@ -5459,6 +6074,103 @@ static struct hda_verb alc262_init_verbs[] = {
5459 { } 6074 { }
5460}; 6075};
5461 6076
6077static struct hda_verb alc262_hippo_unsol_verbs[] = {
6078 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6079 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6080 {}
6081};
6082
6083static struct hda_verb alc262_hippo1_unsol_verbs[] = {
6084 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6085 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
6086 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6087
6088 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6089 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6090 {}
6091};
6092
6093/* mute/unmute internal speaker according to the hp jack and mute state */
6094static void alc262_hippo_automute(struct hda_codec *codec, int force)
6095{
6096 struct alc_spec *spec = codec->spec;
6097 unsigned int mute;
6098
6099 if (force || ! spec->sense_updated) {
6100 unsigned int present;
6101 /* need to execute and sync at first */
6102 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
6103 present = snd_hda_codec_read(codec, 0x15, 0,
6104 AC_VERB_GET_PIN_SENSE, 0);
6105 spec->jack_present = (present & 0x80000000) != 0;
6106 spec->sense_updated = 1;
6107 }
6108 if (spec->jack_present) {
6109 /* mute internal speaker */
6110 snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
6111 0x80, 0x80);
6112 snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
6113 0x80, 0x80);
6114 } else {
6115 /* unmute internal speaker if necessary */
6116 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
6117 snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
6118 0x80, mute & 0x80);
6119 mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0);
6120 snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
6121 0x80, mute & 0x80);
6122 }
6123}
6124
6125/* unsolicited event for HP jack sensing */
6126static void alc262_hippo_unsol_event(struct hda_codec *codec,
6127 unsigned int res)
6128{
6129 if ((res >> 26) != ALC880_HP_EVENT)
6130 return;
6131 alc262_hippo_automute(codec, 1);
6132}
6133
6134static void alc262_hippo1_automute(struct hda_codec *codec, int force)
6135{
6136 struct alc_spec *spec = codec->spec;
6137 unsigned int mute;
6138
6139 if (force || ! spec->sense_updated) {
6140 unsigned int present;
6141 /* need to execute and sync at first */
6142 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
6143 present = snd_hda_codec_read(codec, 0x1b, 0,
6144 AC_VERB_GET_PIN_SENSE, 0);
6145 spec->jack_present = (present & 0x80000000) != 0;
6146 spec->sense_updated = 1;
6147 }
6148 if (spec->jack_present) {
6149 /* mute internal speaker */
6150 snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
6151 0x80, 0x80);
6152 snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
6153 0x80, 0x80);
6154 } else {
6155 /* unmute internal speaker if necessary */
6156 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
6157 snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
6158 0x80, mute & 0x80);
6159 mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0);
6160 snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
6161 0x80, mute & 0x80);
6162 }
6163}
6164
6165/* unsolicited event for HP jack sensing */
6166static void alc262_hippo1_unsol_event(struct hda_codec *codec,
6167 unsigned int res)
6168{
6169 if ((res >> 26) != ALC880_HP_EVENT)
6170 return;
6171 alc262_hippo1_automute(codec, 1);
6172}
6173
5462/* 6174/*
5463 * fujitsu model 6175 * fujitsu model
5464 * 0x14 = headphone/spdif-out, 0x15 = internal speaker 6176 * 0x14 = headphone/spdif-out, 0x15 = internal speaker
@@ -5809,6 +6521,100 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = {
5809 { } 6521 { }
5810}; 6522};
5811 6523
6524static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
6525 /*
6526 * Unmute ADC0-2 and set the default input to mic-in
6527 */
6528 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6529 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6530 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6531 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6532 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6533 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6534
6535 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6536 * mixer widget
6537 * Note: PASD motherboards uses the Line In 2 as the input for front
6538 * panel mic (mic 2)
6539 */
6540 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
6541 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6542 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6543 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
6544 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
6545 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
6546 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
6547 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
6548 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)},
6549 /*
6550 * Set up output mixers (0x0c - 0x0e)
6551 */
6552 /* set vol=0 to output mixers */
6553 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6554 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6555 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6556
6557 /* set up input amps for analog loopback */
6558 /* Amp Indices: DAC = 0, mixer = 1 */
6559 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6560 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6561 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6562 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6563 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6564 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6565
6566
6567 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
6568 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
6569 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
6570 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
6571 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
6572 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
6573 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
6574
6575 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6576 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6577
6578 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
6579 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6580
6581 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
6582 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
6583 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
6584 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
6585 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
6586 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
6587
6588 /* FIXME: use matrix-type input source selection */
6589 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6590 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6591 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
6592 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
6593 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
6594 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
6595 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
6596 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
6597 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
6598 /* Input mixer2 */
6599 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6600 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6601 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
6602 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
6603 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
6604 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
6605 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
6606 /* Input mixer3 */
6607 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6608 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6609 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
6610 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
6611 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
6612 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
6613 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
6614
6615 { }
6616};
6617
5812/* pcm configuration: identiacal with ALC880 */ 6618/* pcm configuration: identiacal with ALC880 */
5813#define alc262_pcm_analog_playback alc880_pcm_analog_playback 6619#define alc262_pcm_analog_playback alc880_pcm_analog_playback
5814#define alc262_pcm_analog_capture alc880_pcm_analog_capture 6620#define alc262_pcm_analog_capture alc880_pcm_analog_capture
@@ -5866,26 +6672,35 @@ static void alc262_auto_init(struct hda_codec *codec)
5866/* 6672/*
5867 * configuration and preset 6673 * configuration and preset
5868 */ 6674 */
5869static struct hda_board_config alc262_cfg_tbl[] = { 6675static const char *alc262_models[ALC262_MODEL_LAST] = {
5870 { .modelname = "basic", .config = ALC262_BASIC }, 6676 [ALC262_BASIC] = "basic",
5871 { .modelname = "fujitsu", .config = ALC262_FUJITSU }, 6677 [ALC262_HIPPO] = "hippo",
5872 { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, 6678 [ALC262_HIPPO_1] = "hippo_1",
5873 .config = ALC262_FUJITSU }, 6679 [ALC262_FUJITSU] = "fujitsu",
5874 { .modelname = "hp-bpc", .config = ALC262_HP_BPC }, 6680 [ALC262_HP_BPC] = "hp-bpc",
5875 { .pci_subvendor = 0x103c, .pci_subdevice = 0x280c, 6681 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
5876 .config = ALC262_HP_BPC }, /* xw4400 */ 6682 [ALC262_BENQ_ED8] = "benq",
5877 { .pci_subvendor = 0x103c, .pci_subdevice = 0x2801, 6683 [ALC262_AUTO] = "auto",
5878 .config = ALC262_HP_BPC }, /* q965 */ 6684};
5879 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, 6685
5880 .config = ALC262_HP_BPC }, /* xw6400 */ 6686static struct snd_pci_quirk alc262_cfg_tbl[] = {
5881 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, 6687 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
5882 .config = ALC262_HP_BPC }, /* xw8400 */ 6688 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
5883 { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe, 6689 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
5884 .config = ALC262_HP_BPC }, /* xw9400 */ 6690 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
5885 { .modelname = "benq", .config = ALC262_BENQ_ED8 }, 6691 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
5886 { .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560, 6692 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
5887 .config = ALC262_BENQ_ED8 }, 6693 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
5888 { .modelname = "auto", .config = ALC262_AUTO }, 6694 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
6695 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
6696 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
6697 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
6698 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
6699 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
6700 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
6701 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
6702 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
6703 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
5889 {} 6704 {}
5890}; 6705};
5891 6706
@@ -5900,6 +6715,30 @@ static struct alc_config_preset alc262_presets[] = {
5900 .channel_mode = alc262_modes, 6715 .channel_mode = alc262_modes,
5901 .input_mux = &alc262_capture_source, 6716 .input_mux = &alc262_capture_source,
5902 }, 6717 },
6718 [ALC262_HIPPO] = {
6719 .mixers = { alc262_base_mixer },
6720 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
6721 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
6722 .dac_nids = alc262_dac_nids,
6723 .hp_nid = 0x03,
6724 .dig_out_nid = ALC262_DIGOUT_NID,
6725 .num_channel_mode = ARRAY_SIZE(alc262_modes),
6726 .channel_mode = alc262_modes,
6727 .input_mux = &alc262_capture_source,
6728 .unsol_event = alc262_hippo_unsol_event,
6729 },
6730 [ALC262_HIPPO_1] = {
6731 .mixers = { alc262_hippo1_mixer },
6732 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
6733 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
6734 .dac_nids = alc262_dac_nids,
6735 .hp_nid = 0x02,
6736 .dig_out_nid = ALC262_DIGOUT_NID,
6737 .num_channel_mode = ARRAY_SIZE(alc262_modes),
6738 .channel_mode = alc262_modes,
6739 .input_mux = &alc262_capture_source,
6740 .unsol_event = alc262_hippo1_unsol_event,
6741 },
5903 [ALC262_FUJITSU] = { 6742 [ALC262_FUJITSU] = {
5904 .mixers = { alc262_fujitsu_mixer }, 6743 .mixers = { alc262_fujitsu_mixer },
5905 .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs }, 6744 .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs },
@@ -5922,6 +6761,27 @@ static struct alc_config_preset alc262_presets[] = {
5922 .channel_mode = alc262_modes, 6761 .channel_mode = alc262_modes,
5923 .input_mux = &alc262_HP_capture_source, 6762 .input_mux = &alc262_HP_capture_source,
5924 }, 6763 },
6764 [ALC262_HP_BPC_D7000_WF] = {
6765 .mixers = { alc262_HP_BPC_WildWest_mixer },
6766 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
6767 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
6768 .dac_nids = alc262_dac_nids,
6769 .hp_nid = 0x03,
6770 .num_channel_mode = ARRAY_SIZE(alc262_modes),
6771 .channel_mode = alc262_modes,
6772 .input_mux = &alc262_HP_capture_source,
6773 },
6774 [ALC262_HP_BPC_D7000_WL] = {
6775 .mixers = { alc262_HP_BPC_WildWest_mixer,
6776 alc262_HP_BPC_WildWest_option_mixer },
6777 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
6778 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
6779 .dac_nids = alc262_dac_nids,
6780 .hp_nid = 0x03,
6781 .num_channel_mode = ARRAY_SIZE(alc262_modes),
6782 .channel_mode = alc262_modes,
6783 .input_mux = &alc262_HP_capture_source,
6784 },
5925 [ALC262_BENQ_ED8] = { 6785 [ALC262_BENQ_ED8] = {
5926 .mixers = { alc262_base_mixer }, 6786 .mixers = { alc262_base_mixer },
5927 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, 6787 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
@@ -5940,7 +6800,7 @@ static int patch_alc262(struct hda_codec *codec)
5940 int board_config; 6800 int board_config;
5941 int err; 6801 int err;
5942 6802
5943 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 6803 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5944 if (spec == NULL) 6804 if (spec == NULL)
5945 return -ENOMEM; 6805 return -ENOMEM;
5946 6806
@@ -5956,9 +6816,11 @@ static int patch_alc262(struct hda_codec *codec)
5956 } 6816 }
5957#endif 6817#endif
5958 6818
5959 board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl); 6819 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
5960 6820 alc262_models,
5961 if (board_config < 0 || board_config >= ALC262_MODEL_LAST) { 6821 alc262_cfg_tbl);
6822
6823 if (board_config < 0) {
5962 printk(KERN_INFO "hda_codec: Unknown model for ALC262, " 6824 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
5963 "trying auto-probe from BIOS...\n"); 6825 "trying auto-probe from BIOS...\n");
5964 board_config = ALC262_AUTO; 6826 board_config = ALC262_AUTO;
@@ -6078,6 +6940,44 @@ static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
6078 { 4, alc861_uniwill_m31_ch4_init }, 6940 { 4, alc861_uniwill_m31_ch4_init },
6079}; 6941};
6080 6942
6943/* Set mic1 and line-in as input and unmute the mixer */
6944static struct hda_verb alc861_asus_ch2_init[] = {
6945 /* set pin widget 1Ah (line in) for input */
6946 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
6947 /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */
6948 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
6949
6950 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
6951#if 0
6952 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
6953 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
6954#endif
6955 { } /* end */
6956};
6957/* Set mic1 nad line-in as output and mute mixer */
6958static struct hda_verb alc861_asus_ch6_init[] = {
6959 /* set pin widget 1Ah (line in) for output (Back Surround)*/
6960 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
6961 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
6962 /* set pin widget 18h (mic1) for output (CLFE)*/
6963 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
6964 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
6965 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
6966 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
6967
6968 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
6969#if 0
6970 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
6971 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
6972#endif
6973 { } /* end */
6974};
6975
6976static struct hda_channel_mode alc861_asus_modes[2] = {
6977 { 2, alc861_asus_ch2_init },
6978 { 6, alc861_asus_ch6_init },
6979};
6980
6081/* patch-ALC861 */ 6981/* patch-ALC861 */
6082 6982
6083static struct snd_kcontrol_new alc861_base_mixer[] = { 6983static struct snd_kcontrol_new alc861_base_mixer[] = {
@@ -6154,7 +7054,29 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = {
6154 .private_value = ARRAY_SIZE(alc861_threestack_modes), 7054 .private_value = ARRAY_SIZE(alc861_threestack_modes),
6155 }, 7055 },
6156 { } /* end */ 7056 { } /* end */
6157}; 7057};
7058
7059static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
7060 /* output mixer control */
7061 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
7062 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
7063 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
7064
7065 /*Capture mixer control */
7066 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7067 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7068 {
7069 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7070 .name = "Capture Source",
7071 .count = 1,
7072 .info = alc_mux_enum_info,
7073 .get = alc_mux_enum_get,
7074 .put = alc_mux_enum_put,
7075 },
7076
7077 { } /* end */
7078};
7079
6158static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { 7080static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
6159 /* output mixer control */ 7081 /* output mixer control */
6160 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), 7082 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
@@ -6196,7 +7118,58 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
6196 }, 7118 },
6197 { } /* end */ 7119 { } /* end */
6198}; 7120};
6199 7121
7122static struct snd_kcontrol_new alc861_asus_mixer[] = {
7123 /* output mixer control */
7124 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
7125 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
7126 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
7127 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
7128 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
7129
7130 /* Input mixer control */
7131 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
7132 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7133 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
7134 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
7135 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
7136 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
7137 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
7138 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
7139 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
7140 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), /* was HDA_INPUT (why?) */
7141
7142 /* Capture mixer control */
7143 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7144 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7145 {
7146 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7147 .name = "Capture Source",
7148 .count = 1,
7149 .info = alc_mux_enum_info,
7150 .get = alc_mux_enum_get,
7151 .put = alc_mux_enum_put,
7152 },
7153 {
7154 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7155 .name = "Channel Mode",
7156 .info = alc_ch_mode_info,
7157 .get = alc_ch_mode_get,
7158 .put = alc_ch_mode_put,
7159 .private_value = ARRAY_SIZE(alc861_asus_modes),
7160 },
7161 { }
7162};
7163
7164/* additional mixer */
7165static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
7166 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
7167 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
7168 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
7169 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
7170 { }
7171};
7172
6200/* 7173/*
6201 * generic initialization of ADC, input mixers and output mixers 7174 * generic initialization of ADC, input mixers and output mixers
6202 */ 7175 */
@@ -6217,7 +7190,7 @@ static struct hda_verb alc861_base_init_verbs[] = {
6217 /* port-E for HP out (front panel) */ 7190 /* port-E for HP out (front panel) */
6218 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, 7191 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
6219 /* route front PCM to HP */ 7192 /* route front PCM to HP */
6220 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, 7193 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
6221 /* port-F for mic-in (front panel) with vref */ 7194 /* port-F for mic-in (front panel) with vref */
6222 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 7195 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
6223 /* port-G for CLFE (rear panel) */ 7196 /* port-G for CLFE (rear panel) */
@@ -6281,7 +7254,7 @@ static struct hda_verb alc861_threestack_init_verbs[] = {
6281 /* port-E for HP out (front panel) */ 7254 /* port-E for HP out (front panel) */
6282 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, 7255 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
6283 /* route front PCM to HP */ 7256 /* route front PCM to HP */
6284 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, 7257 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
6285 /* port-F for mic-in (front panel) with vref */ 7258 /* port-F for mic-in (front panel) with vref */
6286 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 7259 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
6287 /* port-G for CLFE (rear panel) */ 7260 /* port-G for CLFE (rear panel) */
@@ -6341,7 +7314,7 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
6341 /* port-E for HP out (front panel) */ 7314 /* port-E for HP out (front panel) */
6342 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80 7315 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80
6343 /* route front PCM to HP */ 7316 /* route front PCM to HP */
6344 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, 7317 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
6345 /* port-F for mic-in (front panel) with vref */ 7318 /* port-F for mic-in (front panel) with vref */
6346 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, 7319 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
6347 /* port-G for CLFE (rear panel) */ 7320 /* port-G for CLFE (rear panel) */
@@ -6385,6 +7358,74 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
6385 { } 7358 { }
6386}; 7359};
6387 7360
7361static struct hda_verb alc861_asus_init_verbs[] = {
7362 /*
7363 * Unmute ADC0 and set the default input to mic-in
7364 */
7365 /* port-A for surround (rear panel) | according to codec#0 this is the HP jack*/
7366 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
7367 /* route front PCM to HP */
7368 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
7369 /* port-B for mic-in (rear panel) with vref */
7370 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
7371 /* port-C for line-in (rear panel) */
7372 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
7373 /* port-D for Front */
7374 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
7375 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
7376 /* port-E for HP out (front panel) */
7377 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* this has to be set to VREF80 */
7378 /* route front PCM to HP */
7379 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
7380 /* port-F for mic-in (front panel) with vref */
7381 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
7382 /* port-G for CLFE (rear panel) */
7383 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
7384 /* port-H for side (rear panel) */
7385 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
7386 /* CD-in */
7387 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
7388 /* route front mic to ADC1*/
7389 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7390 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7391 /* Unmute DAC0~3 & spdif out*/
7392 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7393 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7394 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7395 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7396 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7397 /* Unmute Mixer 14 (mic) 1c (Line in)*/
7398 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7399 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7400 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7401 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7402
7403 /* Unmute Stereo Mixer 15 */
7404 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7405 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7406 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7407 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, /* Output 0~12 step */
7408
7409 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7410 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7411 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7412 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7413 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7414 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7415 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7416 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7417 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, /* hp used DAC 3 (Front) */
7418 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7419 { }
7420};
7421
7422/* additional init verbs for ASUS laptops */
7423static struct hda_verb alc861_asus_laptop_init_verbs[] = {
7424 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
7425 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
7426 { }
7427};
7428
6388/* 7429/*
6389 * generic initialization of ADC, input mixers and output mixers 7430 * generic initialization of ADC, input mixers and output mixers
6390 */ 7431 */
@@ -6437,6 +7478,39 @@ static struct hda_verb alc861_auto_init_verbs[] = {
6437 { } 7478 { }
6438}; 7479};
6439 7480
7481static struct hda_verb alc861_toshiba_init_verbs[] = {
7482 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
7483
7484 { }
7485};
7486
7487/* toggle speaker-output according to the hp-jack state */
7488static void alc861_toshiba_automute(struct hda_codec *codec)
7489{
7490 unsigned int present;
7491
7492 present = snd_hda_codec_read(codec, 0x0f, 0,
7493 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7494 snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0,
7495 0x80, present ? 0x80 : 0);
7496 snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0,
7497 0x80, present ? 0x80 : 0);
7498 snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3,
7499 0x80, present ? 0 : 0x80);
7500 snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3,
7501 0x80, present ? 0 : 0x80);
7502}
7503
7504static void alc861_toshiba_unsol_event(struct hda_codec *codec,
7505 unsigned int res)
7506{
7507 /* Looks like the unsol event is incompatible with the standard
7508 * definition. 6bit tag is placed at 26 bit!
7509 */
7510 if ((res >> 26) == ALC880_HP_EVENT)
7511 alc861_toshiba_automute(codec);
7512}
7513
6440/* pcm configuration: identiacal with ALC880 */ 7514/* pcm configuration: identiacal with ALC880 */
6441#define alc861_pcm_analog_playback alc880_pcm_analog_playback 7515#define alc861_pcm_analog_playback alc880_pcm_analog_playback
6442#define alc861_pcm_analog_capture alc880_pcm_analog_capture 7516#define alc861_pcm_analog_capture alc880_pcm_analog_capture
@@ -6710,19 +7784,29 @@ static void alc861_auto_init(struct hda_codec *codec)
6710/* 7784/*
6711 * configuration and preset 7785 * configuration and preset
6712 */ 7786 */
6713static struct hda_board_config alc861_cfg_tbl[] = { 7787static const char *alc861_models[ALC861_MODEL_LAST] = {
6714 { .modelname = "3stack", .config = ALC861_3ST }, 7788 [ALC861_3ST] = "3stack",
6715 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, 7789 [ALC660_3ST] = "3stack-660",
6716 .config = ALC861_3ST }, 7790 [ALC861_3ST_DIG] = "3stack-dig",
6717 { .modelname = "3stack-660", .config = ALC660_3ST }, 7791 [ALC861_6ST_DIG] = "6stack-dig",
6718 { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7, 7792 [ALC861_UNIWILL_M31] = "uniwill-m31",
6719 .config = ALC660_3ST }, 7793 [ALC861_TOSHIBA] = "toshiba",
6720 { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, 7794 [ALC861_ASUS] = "asus",
6721 { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, 7795 [ALC861_ASUS_LAPTOP] = "asus-laptop",
6722 { .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31}, 7796 [ALC861_AUTO] = "auto",
6723 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072, 7797};
6724 .config = ALC861_UNIWILL_M31 }, 7798
6725 { .modelname = "auto", .config = ALC861_AUTO }, 7799static struct snd_pci_quirk alc861_cfg_tbl[] = {
7800 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
7801 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
7802 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
7803 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
7804 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660_3ST),
7805 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
7806 SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA),
7807 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
7808 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
7809 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
6726 {} 7810 {}
6727}; 7811};
6728 7812
@@ -6789,8 +7873,48 @@ static struct alc_config_preset alc861_presets[] = {
6789 .adc_nids = alc861_adc_nids, 7873 .adc_nids = alc861_adc_nids,
6790 .input_mux = &alc861_capture_source, 7874 .input_mux = &alc861_capture_source,
6791 }, 7875 },
6792 7876 [ALC861_TOSHIBA] = {
6793}; 7877 .mixers = { alc861_toshiba_mixer },
7878 .init_verbs = { alc861_base_init_verbs, alc861_toshiba_init_verbs },
7879 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
7880 .dac_nids = alc861_dac_nids,
7881 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7882 .channel_mode = alc883_3ST_2ch_modes,
7883 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
7884 .adc_nids = alc861_adc_nids,
7885 .input_mux = &alc861_capture_source,
7886 .unsol_event = alc861_toshiba_unsol_event,
7887 .init_hook = alc861_toshiba_automute,
7888 },
7889 [ALC861_ASUS] = {
7890 .mixers = { alc861_asus_mixer },
7891 .init_verbs = { alc861_asus_init_verbs },
7892 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
7893 .dac_nids = alc861_dac_nids,
7894 .dig_out_nid = ALC861_DIGOUT_NID,
7895 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
7896 .channel_mode = alc861_asus_modes,
7897 .need_dac_fix = 1,
7898 .hp_nid = 0x06,
7899 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
7900 .adc_nids = alc861_adc_nids,
7901 .input_mux = &alc861_capture_source,
7902 },
7903 [ALC861_ASUS_LAPTOP] = {
7904 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
7905 .init_verbs = { alc861_asus_init_verbs,
7906 alc861_asus_laptop_init_verbs },
7907 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
7908 .dac_nids = alc861_dac_nids,
7909 .dig_out_nid = ALC861_DIGOUT_NID,
7910 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7911 .channel_mode = alc883_3ST_2ch_modes,
7912 .need_dac_fix = 1,
7913 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
7914 .adc_nids = alc861_adc_nids,
7915 .input_mux = &alc861_capture_source,
7916 },
7917};
6794 7918
6795 7919
6796static int patch_alc861(struct hda_codec *codec) 7920static int patch_alc861(struct hda_codec *codec)
@@ -6799,15 +7923,17 @@ static int patch_alc861(struct hda_codec *codec)
6799 int board_config; 7923 int board_config;
6800 int err; 7924 int err;
6801 7925
6802 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 7926 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
6803 if (spec == NULL) 7927 if (spec == NULL)
6804 return -ENOMEM; 7928 return -ENOMEM;
6805 7929
6806 codec->spec = spec; 7930 codec->spec = spec;
6807 7931
6808 board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl); 7932 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
7933 alc861_models,
7934 alc861_cfg_tbl);
6809 7935
6810 if (board_config < 0 || board_config >= ALC861_MODEL_LAST) { 7936 if (board_config < 0) {
6811 printk(KERN_INFO "hda_codec: Unknown model for ALC861, " 7937 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
6812 "trying auto-probe from BIOS...\n"); 7938 "trying auto-probe from BIOS...\n");
6813 board_config = ALC861_AUTO; 7939 board_config = ALC861_AUTO;
@@ -6846,19 +7972,706 @@ static int patch_alc861(struct hda_codec *codec)
6846} 7972}
6847 7973
6848/* 7974/*
7975 * ALC861-VD support
7976 *
7977 * Based on ALC882
7978 *
7979 * In addition, an independent DAC
7980 */
7981#define ALC861VD_DIGOUT_NID 0x06
7982
7983static hda_nid_t alc861vd_dac_nids[4] = {
7984 /* front, surr, clfe, side surr */
7985 0x02, 0x03, 0x04, 0x05
7986};
7987
7988/* dac_nids for ALC660vd are in a different order - according to
7989 * Realtek's driver.
7990 * This should probably tesult in a different mixer for 6stack models
7991 * of ALC660vd codecs, but for now there is only 3stack mixer
7992 * - and it is the same as in 861vd.
7993 * adc_nids in ALC660vd are (is) the same as in 861vd
7994 */
7995static hda_nid_t alc660vd_dac_nids[3] = {
7996 /* front, rear, clfe, rear_surr */
7997 0x02, 0x04, 0x03
7998};
7999
8000static hda_nid_t alc861vd_adc_nids[1] = {
8001 /* ADC0 */
8002 0x09,
8003};
8004
8005/* input MUX */
8006/* FIXME: should be a matrix-type input source selection */
8007static struct hda_input_mux alc861vd_capture_source = {
8008 .num_items = 4,
8009 .items = {
8010 { "Mic", 0x0 },
8011 { "Front Mic", 0x1 },
8012 { "Line", 0x2 },
8013 { "CD", 0x4 },
8014 },
8015};
8016
8017#define alc861vd_mux_enum_info alc_mux_enum_info
8018#define alc861vd_mux_enum_get alc_mux_enum_get
8019
8020static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
8021 struct snd_ctl_elem_value *ucontrol)
8022{
8023 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8024 struct alc_spec *spec = codec->spec;
8025 const struct hda_input_mux *imux = spec->input_mux;
8026 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
8027 static hda_nid_t capture_mixers[1] = { 0x22 };
8028 hda_nid_t nid = capture_mixers[adc_idx];
8029 unsigned int *cur_val = &spec->cur_mux[adc_idx];
8030 unsigned int i, idx;
8031
8032 idx = ucontrol->value.enumerated.item[0];
8033 if (idx >= imux->num_items)
8034 idx = imux->num_items - 1;
8035 if (*cur_val == idx && ! codec->in_resume)
8036 return 0;
8037 for (i = 0; i < imux->num_items; i++) {
8038 unsigned int v = (i == idx) ? 0x7000 : 0x7080;
8039 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8040 v | (imux->items[i].index << 8));
8041 }
8042 *cur_val = idx;
8043 return 1;
8044}
8045
8046/*
8047 * 2ch mode
8048 */
8049static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
8050 { 2, NULL }
8051};
8052
8053/*
8054 * 6ch mode
8055 */
8056static struct hda_verb alc861vd_6stack_ch6_init[] = {
8057 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
8058 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8059 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8060 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8061 { } /* end */
8062};
8063
8064/*
8065 * 8ch mode
8066 */
8067static struct hda_verb alc861vd_6stack_ch8_init[] = {
8068 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8069 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8070 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8071 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8072 { } /* end */
8073};
8074
8075static struct hda_channel_mode alc861vd_6stack_modes[2] = {
8076 { 6, alc861vd_6stack_ch6_init },
8077 { 8, alc861vd_6stack_ch8_init },
8078};
8079
8080static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
8081 {
8082 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8083 .name = "Channel Mode",
8084 .info = alc_ch_mode_info,
8085 .get = alc_ch_mode_get,
8086 .put = alc_ch_mode_put,
8087 },
8088 { } /* end */
8089};
8090
8091static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
8092 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
8093 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
8094
8095 {
8096 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8097 /* The multiple "Capture Source" controls confuse alsamixer
8098 * So call somewhat different..
8099 *FIXME: the controls appear in the "playback" view!
8100 */
8101 /* .name = "Capture Source", */
8102 .name = "Input Source",
8103 .count = 1,
8104 .info = alc861vd_mux_enum_info,
8105 .get = alc861vd_mux_enum_get,
8106 .put = alc861vd_mux_enum_put,
8107 },
8108 { } /* end */
8109};
8110
8111/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
8112 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
8113 */
8114static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
8115 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
8116 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8117
8118 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
8119 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8120
8121 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
8122 HDA_OUTPUT),
8123 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
8124 HDA_OUTPUT),
8125 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8126 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8127
8128 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
8129 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8130
8131 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8132
8133 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8134 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8135 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8136
8137 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8138 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8139 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8140
8141 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8142 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8143
8144 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8145 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8146
8147 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
8148 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
8149
8150 { } /* end */
8151};
8152
8153static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
8154 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
8155 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8156
8157 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8158
8159 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8160 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8161 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8162
8163 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8164 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8165 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8166
8167 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8168 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8169
8170 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8171 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8172
8173 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
8174 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
8175
8176 { } /* end */
8177};
8178
8179/*
8180 * generic initialization of ADC, input mixers and output mixers
8181 */
8182static struct hda_verb alc861vd_volume_init_verbs[] = {
8183 /*
8184 * Unmute ADC0 and set the default input to mic-in
8185 */
8186 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8187 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8188
8189 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
8190 * the analog-loopback mixer widget
8191 */
8192 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
8193 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8194 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8195 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8196 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8197 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8198
8199 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
8200 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8201 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
8202 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
8203 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(8)},
8204
8205 /*
8206 * Set up output mixers (0x02 - 0x05)
8207 */
8208 /* set vol=0 to output mixers */
8209 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8210 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8211 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8212 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8213
8214 /* set up input amps for analog loopback */
8215 /* Amp Indices: DAC = 0, mixer = 1 */
8216 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8217 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8218 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8219 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8220 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8221 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8222 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8223 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8224
8225 { }
8226};
8227
8228/*
8229 * 3-stack pin configuration:
8230 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
8231 */
8232static struct hda_verb alc861vd_3stack_init_verbs[] = {
8233 /*
8234 * Set pin mode and muting
8235 */
8236 /* set front pin widgets 0x14 for output */
8237 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8238 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8239 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8240
8241 /* Mic (rear) pin: input vref at 80% */
8242 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8243 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8244 /* Front Mic pin: input vref at 80% */
8245 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8246 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8247 /* Line In pin: input */
8248 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8249 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8250 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8251 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8252 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8253 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8254 /* CD pin widget for input */
8255 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8256
8257 { }
8258};
8259
8260/*
8261 * 6-stack pin configuration:
8262 */
8263static struct hda_verb alc861vd_6stack_init_verbs[] = {
8264 /*
8265 * Set pin mode and muting
8266 */
8267 /* set front pin widgets 0x14 for output */
8268 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8269 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8270 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8271
8272 /* Rear Pin: output 1 (0x0d) */
8273 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8274 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8275 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8276 /* CLFE Pin: output 2 (0x0e) */
8277 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8278 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8279 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8280 /* Side Pin: output 3 (0x0f) */
8281 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8282 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8283 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8284
8285 /* Mic (rear) pin: input vref at 80% */
8286 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8287 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8288 /* Front Mic pin: input vref at 80% */
8289 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8290 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8291 /* Line In pin: input */
8292 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8293 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8294 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8295 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8296 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8297 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8298 /* CD pin widget for input */
8299 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8300
8301 { }
8302};
8303
8304/* pcm configuration: identiacal with ALC880 */
8305#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
8306#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
8307#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
8308#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
8309
8310/*
8311 * configuration and preset
8312 */
8313static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
8314 [ALC660VD_3ST] = "3stack-660",
8315 [ALC861VD_3ST] = "3stack",
8316 [ALC861VD_3ST_DIG] = "3stack-digout",
8317 [ALC861VD_6ST_DIG] = "6stack-digout",
8318 [ALC861VD_AUTO] = "auto",
8319};
8320
8321static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
8322 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
8323 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
8324 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
8325
8326 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_3ST),
8327 {}
8328};
8329
8330static struct alc_config_preset alc861vd_presets[] = {
8331 [ALC660VD_3ST] = {
8332 .mixers = { alc861vd_3st_mixer },
8333 .init_verbs = { alc861vd_volume_init_verbs,
8334 alc861vd_3stack_init_verbs },
8335 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
8336 .dac_nids = alc660vd_dac_nids,
8337 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
8338 .adc_nids = alc861vd_adc_nids,
8339 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
8340 .channel_mode = alc861vd_3stack_2ch_modes,
8341 .input_mux = &alc861vd_capture_source,
8342 },
8343 [ALC861VD_3ST] = {
8344 .mixers = { alc861vd_3st_mixer },
8345 .init_verbs = { alc861vd_volume_init_verbs,
8346 alc861vd_3stack_init_verbs },
8347 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
8348 .dac_nids = alc861vd_dac_nids,
8349 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
8350 .channel_mode = alc861vd_3stack_2ch_modes,
8351 .input_mux = &alc861vd_capture_source,
8352 },
8353 [ALC861VD_3ST_DIG] = {
8354 .mixers = { alc861vd_3st_mixer },
8355 .init_verbs = { alc861vd_volume_init_verbs,
8356 alc861vd_3stack_init_verbs },
8357 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
8358 .dac_nids = alc861vd_dac_nids,
8359 .dig_out_nid = ALC861VD_DIGOUT_NID,
8360 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
8361 .channel_mode = alc861vd_3stack_2ch_modes,
8362 .input_mux = &alc861vd_capture_source,
8363 },
8364 [ALC861VD_6ST_DIG] = {
8365 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
8366 .init_verbs = { alc861vd_volume_init_verbs,
8367 alc861vd_6stack_init_verbs },
8368 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
8369 .dac_nids = alc861vd_dac_nids,
8370 .dig_out_nid = ALC861VD_DIGOUT_NID,
8371 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
8372 .channel_mode = alc861vd_6stack_modes,
8373 .input_mux = &alc861vd_capture_source,
8374 },
8375};
8376
8377/*
8378 * BIOS auto configuration
8379 */
8380static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
8381 hda_nid_t nid, int pin_type, int dac_idx)
8382{
8383 /* set as output */
8384 snd_hda_codec_write(codec, nid, 0,
8385 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
8386 snd_hda_codec_write(codec, nid, 0,
8387 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
8388}
8389
8390static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
8391{
8392 struct alc_spec *spec = codec->spec;
8393 int i;
8394
8395 for (i = 0; i <= HDA_SIDE; i++) {
8396 hda_nid_t nid = spec->autocfg.line_out_pins[i];
8397 if (nid)
8398 alc861vd_auto_set_output_and_unmute(codec, nid,
8399 PIN_OUT, i);
8400 }
8401}
8402
8403
8404static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
8405{
8406 struct alc_spec *spec = codec->spec;
8407 hda_nid_t pin;
8408
8409 pin = spec->autocfg.hp_pins[0];
8410 if (pin) /* connect to front and use dac 0 */
8411 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
8412}
8413
8414#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
8415#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
8416
8417static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
8418{
8419 struct alc_spec *spec = codec->spec;
8420 int i;
8421
8422 for (i = 0; i < AUTO_PIN_LAST; i++) {
8423 hda_nid_t nid = spec->autocfg.input_pins[i];
8424 if (alc861vd_is_input_pin(nid)) {
8425 snd_hda_codec_write(codec, nid, 0,
8426 AC_VERB_SET_PIN_WIDGET_CONTROL,
8427 i <= AUTO_PIN_FRONT_MIC ?
8428 PIN_VREF80 : PIN_IN);
8429 if (nid != ALC861VD_PIN_CD_NID)
8430 snd_hda_codec_write(codec, nid, 0,
8431 AC_VERB_SET_AMP_GAIN_MUTE,
8432 AMP_OUT_MUTE);
8433 }
8434 }
8435}
8436
8437#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
8438#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
8439
8440/* add playback controls from the parsed DAC table */
8441/* Based on ALC880 version. But ALC861VD has separate,
8442 * different NIDs for mute/unmute switch and volume control */
8443static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
8444 const struct auto_pin_cfg *cfg)
8445{
8446 char name[32];
8447 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
8448 hda_nid_t nid_v, nid_s;
8449 int i, err;
8450
8451 for (i = 0; i < cfg->line_outs; i++) {
8452 if (! spec->multiout.dac_nids[i])
8453 continue;
8454 nid_v = alc861vd_idx_to_mixer_vol(
8455 alc880_dac_to_idx(
8456 spec->multiout.dac_nids[i]));
8457 nid_s = alc861vd_idx_to_mixer_switch(
8458 alc880_dac_to_idx(
8459 spec->multiout.dac_nids[i]));
8460
8461 if (i == 2) {
8462 /* Center/LFE */
8463 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL,
8464 "Center Playback Volume",
8465 HDA_COMPOSE_AMP_VAL(nid_v, 1,
8466 0, HDA_OUTPUT))) < 0)
8467 return err;
8468 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL,
8469 "LFE Playback Volume",
8470 HDA_COMPOSE_AMP_VAL(nid_v, 2,
8471 0, HDA_OUTPUT))) < 0)
8472 return err;
8473 if ((err = add_control(spec, ALC_CTL_BIND_MUTE,
8474 "Center Playback Switch",
8475 HDA_COMPOSE_AMP_VAL(nid_s, 1,
8476 2, HDA_INPUT))) < 0)
8477 return err;
8478 if ((err = add_control(spec, ALC_CTL_BIND_MUTE,
8479 "LFE Playback Switch",
8480 HDA_COMPOSE_AMP_VAL(nid_s, 2,
8481 2, HDA_INPUT))) < 0)
8482 return err;
8483 } else {
8484 sprintf(name, "%s Playback Volume", chname[i]);
8485 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
8486 HDA_COMPOSE_AMP_VAL(nid_v, 3,
8487 0, HDA_OUTPUT))) < 0)
8488 return err;
8489 sprintf(name, "%s Playback Switch", chname[i]);
8490 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
8491 HDA_COMPOSE_AMP_VAL(nid_v, 3,
8492 2, HDA_INPUT))) < 0)
8493 return err;
8494 }
8495 }
8496 return 0;
8497}
8498
8499/* add playback controls for speaker and HP outputs */
8500/* Based on ALC880 version. But ALC861VD has separate,
8501 * different NIDs for mute/unmute switch and volume control */
8502static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
8503 hda_nid_t pin, const char *pfx)
8504{
8505 hda_nid_t nid_v, nid_s;
8506 int err;
8507 char name[32];
8508
8509 if (! pin)
8510 return 0;
8511
8512 if (alc880_is_fixed_pin(pin)) {
8513 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
8514 /* specify the DAC as the extra output */
8515 if (! spec->multiout.hp_nid)
8516 spec->multiout.hp_nid = nid_v;
8517 else
8518 spec->multiout.extra_out_nid[0] = nid_v;
8519 /* control HP volume/switch on the output mixer amp */
8520 nid_v = alc861vd_idx_to_mixer_vol(
8521 alc880_fixed_pin_idx(pin));
8522 nid_s = alc861vd_idx_to_mixer_switch(
8523 alc880_fixed_pin_idx(pin));
8524
8525 sprintf(name, "%s Playback Volume", pfx);
8526 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
8527 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
8528 HDA_OUTPUT))) < 0)
8529 return err;
8530 sprintf(name, "%s Playback Switch", pfx);
8531 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
8532 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
8533 HDA_INPUT))) < 0)
8534 return err;
8535 } else if (alc880_is_multi_pin(pin)) {
8536 /* set manual connection */
8537 /* we have only a switch on HP-out PIN */
8538 sprintf(name, "%s Playback Switch", pfx);
8539 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
8540 HDA_COMPOSE_AMP_VAL(pin, 3, 0,
8541 HDA_OUTPUT))) < 0)
8542 return err;
8543 }
8544 return 0;
8545}
8546
8547/* parse the BIOS configuration and set up the alc_spec
8548 * return 1 if successful, 0 if the proper config is not found,
8549 * or a negative error code
8550 * Based on ALC880 version - had to change it to override
8551 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
8552static int alc861vd_parse_auto_config(struct hda_codec *codec)
8553{
8554 struct alc_spec *spec = codec->spec;
8555 int err;
8556 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
8557
8558 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
8559 alc861vd_ignore)) < 0)
8560 return err;
8561 if (! spec->autocfg.line_outs)
8562 return 0; /* can't find valid BIOS pin config */
8563
8564 if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
8565 (err = alc861vd_auto_create_multi_out_ctls(spec,
8566 &spec->autocfg)) < 0 ||
8567 (err = alc861vd_auto_create_extra_out(spec,
8568 spec->autocfg.speaker_pins[0], "Speaker")) < 0 ||
8569 (err = alc861vd_auto_create_extra_out(spec,
8570 spec->autocfg.hp_pins[0], "Headphone")) < 0 ||
8571 (err = alc880_auto_create_analog_input_ctls(spec,
8572 &spec->autocfg)) < 0)
8573 return err;
8574
8575 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
8576
8577 if (spec->autocfg.dig_out_pin)
8578 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
8579
8580 if (spec->kctl_alloc)
8581 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
8582
8583 spec->init_verbs[spec->num_init_verbs++]
8584 = alc861vd_volume_init_verbs;
8585
8586 spec->num_mux_defs = 1;
8587 spec->input_mux = &spec->private_imux;
8588
8589 return 1;
8590}
8591
8592/* additional initialization for auto-configuration model */
8593static void alc861vd_auto_init(struct hda_codec *codec)
8594{
8595 alc861vd_auto_init_multi_out(codec);
8596 alc861vd_auto_init_hp_out(codec);
8597 alc861vd_auto_init_analog_input(codec);
8598}
8599
8600static int patch_alc861vd(struct hda_codec *codec)
8601{
8602 struct alc_spec *spec;
8603 int err, board_config;
8604
8605 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8606 if (spec == NULL)
8607 return -ENOMEM;
8608
8609 codec->spec = spec;
8610
8611 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
8612 alc861vd_models,
8613 alc861vd_cfg_tbl);
8614
8615 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
8616 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
8617 "ALC861VD, trying auto-probe from BIOS...\n");
8618 board_config = ALC861VD_AUTO;
8619 }
8620
8621 if (board_config == ALC861VD_AUTO) {
8622 /* automatic parse from the BIOS config */
8623 err = alc861vd_parse_auto_config(codec);
8624 if (err < 0) {
8625 alc_free(codec);
8626 return err;
8627 } else if (! err) {
8628 printk(KERN_INFO
8629 "hda_codec: Cannot set up configuration "
8630 "from BIOS. Using base mode...\n");
8631 board_config = ALC861VD_3ST;
8632 }
8633 }
8634
8635 if (board_config != ALC861VD_AUTO)
8636 setup_preset(spec, &alc861vd_presets[board_config]);
8637
8638 spec->stream_name_analog = "ALC861VD Analog";
8639 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
8640 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
8641
8642 spec->stream_name_digital = "ALC861VD Digital";
8643 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
8644 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
8645
8646 spec->adc_nids = alc861vd_adc_nids;
8647 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
8648
8649 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
8650 spec->num_mixers++;
8651
8652 codec->patch_ops = alc_patch_ops;
8653
8654 if (board_config == ALC861VD_AUTO)
8655 spec->init_hook = alc861vd_auto_init;
8656
8657 return 0;
8658}
8659
8660/*
6849 * patch entries 8661 * patch entries
6850 */ 8662 */
6851struct hda_codec_preset snd_hda_preset_realtek[] = { 8663struct hda_codec_preset snd_hda_preset_realtek[] = {
6852 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, 8664 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
6853 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, 8665 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
6854 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, 8666 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
8667 .patch = patch_alc861 },
8668 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
8669 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
8670 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
8671 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
6855 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, 8672 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
6856 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, 8673 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
6857 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, 8674 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
6858 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, 8675 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
6859 { .id = 0x10ec0861, .rev = 0x100300, .name = "ALC861",
6860 .patch = patch_alc861 },
6861 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
6862 .patch = patch_alc861 },
6863 {} /* terminator */ 8676 {} /* terminator */
6864}; 8677};
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index fe51ef3e49d2..6f4a39273b98 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -37,14 +37,37 @@
37#define NUM_CONTROL_ALLOC 32 37#define NUM_CONTROL_ALLOC 32
38#define STAC_HP_EVENT 0x37 38#define STAC_HP_EVENT 0x37
39 39
40#define STAC_REF 0 40enum {
41#define STAC_D945GTP3 1 41 STAC_REF,
42#define STAC_D945GTP5 2 42 STAC_9200_MODELS
43#define STAC_MACMINI 3 43};
44#define STAC_922X_MODELS 4 /* number of 922x models */ 44
45#define STAC_D965_3ST 4 45enum {
46#define STAC_D965_5ST 5 46 STAC_9205_REF,
47#define STAC_927X_MODELS 6 /* number of 922x models */ 47 STAC_9205_MODELS
48};
49
50enum {
51 STAC_925x_REF,
52 STAC_M2_2,
53 STAC_MA6,
54 STAC_925x_MODELS
55};
56
57enum {
58 STAC_D945_REF,
59 STAC_D945GTP3,
60 STAC_D945GTP5,
61 STAC_MACMINI,
62 STAC_922X_MODELS
63};
64
65enum {
66 STAC_D965_REF,
67 STAC_D965_3ST,
68 STAC_D965_5ST,
69 STAC_927X_MODELS
70};
48 71
49struct sigmatel_spec { 72struct sigmatel_spec {
50 struct snd_kcontrol_new *mixers[4]; 73 struct snd_kcontrol_new *mixers[4];
@@ -67,6 +90,9 @@ struct sigmatel_spec {
67 unsigned int num_adcs; 90 unsigned int num_adcs;
68 hda_nid_t *mux_nids; 91 hda_nid_t *mux_nids;
69 unsigned int num_muxes; 92 unsigned int num_muxes;
93 hda_nid_t *dmic_nids;
94 unsigned int num_dmics;
95 hda_nid_t dmux_nid;
70 hda_nid_t dig_in_nid; 96 hda_nid_t dig_in_nid;
71 97
72 /* pin widgets */ 98 /* pin widgets */
@@ -80,6 +106,8 @@ struct sigmatel_spec {
80 struct snd_kcontrol_new *mixer; 106 struct snd_kcontrol_new *mixer;
81 107
82 /* capture source */ 108 /* capture source */
109 struct hda_input_mux *dinput_mux;
110 unsigned int cur_dmux;
83 struct hda_input_mux *input_mux; 111 struct hda_input_mux *input_mux;
84 unsigned int cur_mux[3]; 112 unsigned int cur_mux[3];
85 113
@@ -92,6 +120,7 @@ struct sigmatel_spec {
92 struct auto_pin_cfg autocfg; 120 struct auto_pin_cfg autocfg;
93 unsigned int num_kctl_alloc, num_kctl_used; 121 unsigned int num_kctl_alloc, num_kctl_used;
94 struct snd_kcontrol_new *kctl_alloc; 122 struct snd_kcontrol_new *kctl_alloc;
123 struct hda_input_mux private_dimux;
95 struct hda_input_mux private_imux; 124 struct hda_input_mux private_imux;
96}; 125};
97 126
@@ -107,6 +136,18 @@ static hda_nid_t stac9200_dac_nids[1] = {
107 0x02, 136 0x02,
108}; 137};
109 138
139static hda_nid_t stac925x_adc_nids[1] = {
140 0x03,
141};
142
143static hda_nid_t stac925x_mux_nids[1] = {
144 0x0f,
145};
146
147static hda_nid_t stac925x_dac_nids[1] = {
148 0x02,
149};
150
110static hda_nid_t stac922x_adc_nids[2] = { 151static hda_nid_t stac922x_adc_nids[2] = {
111 0x06, 0x07, 152 0x06, 0x07,
112}; 153};
@@ -131,11 +172,20 @@ static hda_nid_t stac9205_mux_nids[2] = {
131 0x19, 0x1a 172 0x19, 0x1a
132}; 173};
133 174
175static hda_nid_t stac9205_dmic_nids[3] = {
176 0x17, 0x18, 0
177};
178
134static hda_nid_t stac9200_pin_nids[8] = { 179static hda_nid_t stac9200_pin_nids[8] = {
135 0x08, 0x09, 0x0d, 0x0e, 180 0x08, 0x09, 0x0d, 0x0e,
136 0x0f, 0x10, 0x11, 0x12, 181 0x0f, 0x10, 0x11, 0x12,
137}; 182};
138 183
184static hda_nid_t stac925x_pin_nids[8] = {
185 0x07, 0x08, 0x0a, 0x0b,
186 0x0c, 0x0d, 0x10, 0x11,
187};
188
139static hda_nid_t stac922x_pin_nids[10] = { 189static hda_nid_t stac922x_pin_nids[10] = {
140 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 190 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
141 0x0f, 0x10, 0x11, 0x15, 0x1b, 191 0x0f, 0x10, 0x11, 0x15, 0x1b,
@@ -154,6 +204,34 @@ static hda_nid_t stac9205_pin_nids[12] = {
154 204
155}; 205};
156 206
207static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
208 struct snd_ctl_elem_info *uinfo)
209{
210 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
211 struct sigmatel_spec *spec = codec->spec;
212 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
213}
214
215static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
216 struct snd_ctl_elem_value *ucontrol)
217{
218 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
219 struct sigmatel_spec *spec = codec->spec;
220
221 ucontrol->value.enumerated.item[0] = spec->cur_dmux;
222 return 0;
223}
224
225static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
226 struct snd_ctl_elem_value *ucontrol)
227{
228 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
229 struct sigmatel_spec *spec = codec->spec;
230
231 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
232 spec->dmux_nid, &spec->cur_dmux);
233}
234
157static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 235static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
158{ 236{
159 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 237 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -187,6 +265,12 @@ static struct hda_verb stac9200_core_init[] = {
187 {} 265 {}
188}; 266};
189 267
268static struct hda_verb stac925x_core_init[] = {
269 /* set dac0mux for dac converter */
270 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
271 {}
272};
273
190static struct hda_verb stac922x_core_init[] = { 274static struct hda_verb stac922x_core_init[] = {
191 /* set master volume and direct control */ 275 /* set master volume and direct control */
192 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, 276 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -232,6 +316,23 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
232 { } /* end */ 316 { } /* end */
233}; 317};
234 318
319static struct snd_kcontrol_new stac925x_mixer[] = {
320 HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
321 HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT),
322 {
323 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
324 .name = "Input Source",
325 .count = 1,
326 .info = stac92xx_mux_enum_info,
327 .get = stac92xx_mux_enum_get,
328 .put = stac92xx_mux_enum_put,
329 },
330 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
331 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
332 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
333 { } /* end */
334};
335
235/* This needs to be generated dynamically based on sequence */ 336/* This needs to be generated dynamically based on sequence */
236static struct snd_kcontrol_new stac922x_mixer[] = { 337static struct snd_kcontrol_new stac922x_mixer[] = {
237 { 338 {
@@ -263,7 +364,7 @@ static struct snd_kcontrol_new stac9227_mixer[] = {
263 { } /* end */ 364 { } /* end */
264}; 365};
265 366
266static snd_kcontrol_new_t stac927x_mixer[] = { 367static struct snd_kcontrol_new stac927x_mixer[] = {
267 { 368 {
268 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 369 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
269 .name = "Input Source", 370 .name = "Input Source",
@@ -278,7 +379,15 @@ static snd_kcontrol_new_t stac927x_mixer[] = {
278 { } /* end */ 379 { } /* end */
279}; 380};
280 381
281static snd_kcontrol_new_t stac9205_mixer[] = { 382static struct snd_kcontrol_new stac9205_mixer[] = {
383 {
384 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
385 .name = "Digital Input Source",
386 .count = 1,
387 .info = stac92xx_dmux_enum_info,
388 .get = stac92xx_dmux_enum_get,
389 .put = stac92xx_dmux_enum_put,
390 },
282 { 391 {
283 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 392 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
284 .name = "Input Source", 393 .name = "Input Source",
@@ -327,22 +436,64 @@ static unsigned int ref9200_pin_configs[8] = {
327 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, 436 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
328}; 437};
329 438
330static unsigned int *stac9200_brd_tbl[] = { 439static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
331 ref9200_pin_configs, 440 [STAC_REF] = ref9200_pin_configs,
441};
442
443static const char *stac9200_models[STAC_9200_MODELS] = {
444 [STAC_REF] = "ref",
332}; 445};
333 446
334static struct hda_board_config stac9200_cfg_tbl[] = { 447static struct snd_pci_quirk stac9200_cfg_tbl[] = {
335 { .modelname = "ref", 448 /* SigmaTel reference board */
336 .pci_subvendor = PCI_VENDOR_ID_INTEL, 449 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
337 .pci_subdevice = 0x2668, /* DFI LanParty */ 450 "DFI LanParty", STAC_REF),
338 .config = STAC_REF },
339 /* Dell laptops have BIOS problem */ 451 /* Dell laptops have BIOS problem */
340 { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01b5, 452 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
341 .config = STAC_REF }, /* Dell Inspiron 630m */ 453 "Dell Inspiron 630m", STAC_REF),
342 { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01c2, 454 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
343 .config = STAC_REF }, /* Dell Latitude D620 */ 455 "Dell Latitude D620", STAC_REF),
344 { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01cb, 456 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
345 .config = STAC_REF }, /* Dell Latitude 120L */ 457 "Dell Latitude 120L", STAC_REF),
458 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
459 "Dell Latitude D820", STAC_REF),
460 {} /* terminator */
461};
462
463static unsigned int ref925x_pin_configs[8] = {
464 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
465 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
466};
467
468static unsigned int stac925x_MA6_pin_configs[8] = {
469 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
470 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
471};
472
473static unsigned int stac925xM2_2_pin_configs[8] = {
474 0x40c003f3, 0x424503f2, 0x041800f4, 0x02a19020,
475 0x50a103F0, 0x90100210, 0x400003f1, 0x9033032e,
476};
477
478static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
479 [STAC_REF] = ref925x_pin_configs,
480 [STAC_M2_2] = stac925xM2_2_pin_configs,
481 [STAC_MA6] = stac925x_MA6_pin_configs,
482};
483
484static const char *stac925x_models[STAC_925x_MODELS] = {
485 [STAC_REF] = "ref",
486 [STAC_M2_2] = "m2-2",
487 [STAC_MA6] = "m6",
488};
489
490static struct snd_pci_quirk stac925x_cfg_tbl[] = {
491 /* SigmaTel reference board */
492 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
493 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
494 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
495 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
496 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
346 {} /* terminator */ 497 {} /* terminator */
347}; 498};
348 499
@@ -365,100 +516,80 @@ static unsigned int d945gtp5_pin_configs[10] = {
365}; 516};
366 517
367static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { 518static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
368 [STAC_REF] = ref922x_pin_configs, 519 [STAC_D945_REF] = ref922x_pin_configs,
369 [STAC_D945GTP3] = d945gtp3_pin_configs, 520 [STAC_D945GTP3] = d945gtp3_pin_configs,
370 [STAC_D945GTP5] = d945gtp5_pin_configs, 521 [STAC_D945GTP5] = d945gtp5_pin_configs,
371 [STAC_MACMINI] = d945gtp5_pin_configs, 522 [STAC_MACMINI] = d945gtp5_pin_configs,
372}; 523};
373 524
374static struct hda_board_config stac922x_cfg_tbl[] = { 525static const char *stac922x_models[STAC_922X_MODELS] = {
375 { .modelname = "5stack", .config = STAC_D945GTP5 }, 526 [STAC_D945_REF] = "ref",
376 { .modelname = "3stack", .config = STAC_D945GTP3 }, 527 [STAC_D945GTP5] = "5stack",
377 { .modelname = "ref", 528 [STAC_D945GTP3] = "3stack",
378 .pci_subvendor = PCI_VENDOR_ID_INTEL, 529 [STAC_MACMINI] = "macmini",
379 .pci_subdevice = 0x2668, /* DFI LanParty */ 530};
380 .config = STAC_REF }, /* SigmaTel reference board */ 531
381 /* Intel 945G based systems */ 532static struct snd_pci_quirk stac922x_cfg_tbl[] = {
382 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 533 /* SigmaTel reference board */
383 .pci_subdevice = 0x0101, 534 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
384 .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ 535 "DFI LanParty", STAC_D945_REF),
385 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 536 /* Intel 945G based systems */
386 .pci_subdevice = 0x0202, 537 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
387 .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack */ 538 "Intel D945G", STAC_D945GTP3),
388 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 539 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
389 .pci_subdevice = 0x0606, 540 "Intel D945G", STAC_D945GTP3),
390 .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ 541 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
391 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 542 "Intel D945G", STAC_D945GTP3),
392 .pci_subdevice = 0x0601, 543 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
393 .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ 544 "Intel D945G", STAC_D945GTP3),
394 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 545 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
395 .pci_subdevice = 0x0111, 546 "Intel D945G", STAC_D945GTP3),
396 .config = STAC_D945GTP3 }, /* Intel D945GZP - 3 Stack */ 547 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
397 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 548 "Intel D945G", STAC_D945GTP3),
398 .pci_subdevice = 0x1115, 549 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
399 .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ 550 "Intel D945G", STAC_D945GTP3),
400 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 551 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
401 .pci_subdevice = 0x1116, 552 "Intel D945G", STAC_D945GTP3),
402 .config = STAC_D945GTP3 }, /* Intel D945GBO - 3 Stack */ 553 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
403 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 554 "Intel D945G", STAC_D945GTP3),
404 .pci_subdevice = 0x1117, 555 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
405 .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ 556 "Intel D945G", STAC_D945GTP3),
406 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 557 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
407 .pci_subdevice = 0x1118, 558 "Intel D945G", STAC_D945GTP3),
408 .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ 559 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
409 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 560 "Intel D945G", STAC_D945GTP3),
410 .pci_subdevice = 0x1119, 561 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
411 .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ 562 "Intel D945G", STAC_D945GTP3),
412 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 563 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
413 .pci_subdevice = 0x8826, 564 "Intel D945G", STAC_D945GTP3),
414 .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ 565 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
415 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 566 "Intel D945G", STAC_D945GTP3),
416 .pci_subdevice = 0x5049, 567 /* Intel D945G 5-stack systems */
417 .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ 568 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
418 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 569 "Intel D945G", STAC_D945GTP5),
419 .pci_subdevice = 0x5055, 570 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
420 .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ 571 "Intel D945G", STAC_D945GTP5),
421 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 572 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
422 .pci_subdevice = 0x5048, 573 "Intel D945G", STAC_D945GTP5),
423 .config = STAC_D945GTP3 }, /* Intel D945GPB - 3 Stack */ 574 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
424 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 575 "Intel D945G", STAC_D945GTP5),
425 .pci_subdevice = 0x0110, 576 /* Intel 945P based systems */
426 .config = STAC_D945GTP3 }, /* Intel D945GLR - 3 Stack */ 577 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
427 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 578 "Intel D945P", STAC_D945GTP3),
428 .pci_subdevice = 0x0404, 579 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
429 .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ 580 "Intel D945P", STAC_D945GTP3),
430 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 581 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
431 .pci_subdevice = 0x0303, 582 "Intel D945P", STAC_D945GTP3),
432 .config = STAC_D945GTP5 }, /* Intel D945GNT - 5 Stack */ 583 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
433 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 584 "Intel D945P", STAC_D945GTP3),
434 .pci_subdevice = 0x0013, 585 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
435 .config = STAC_D945GTP5 }, /* Intel D955XBK - 5 Stack */ 586 "Intel D945P", STAC_D945GTP3),
436 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 587 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
437 .pci_subdevice = 0x0417, 588 "Intel D945P", STAC_D945GTP5),
438 .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */ 589 /* other systems */
439 /* Intel 945P based systems */ 590 /* Apple Mac Mini (early 2006) */
440 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 591 SND_PCI_QUIRK(0x8384, 0x7680,
441 .pci_subdevice = 0x0b0b, 592 "Mac Mini", STAC_MACMINI),
442 .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack */
443 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
444 .pci_subdevice = 0x0112,
445 .config = STAC_D945GTP3 }, /* Intel D945PLN - 3 Stack */
446 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
447 .pci_subdevice = 0x0d0d,
448 .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */
449 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
450 .pci_subdevice = 0x0909,
451 .config = STAC_D945GTP3 }, /* Intel D945PAW - 3 Stack */
452 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
453 .pci_subdevice = 0x0505,
454 .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */
455 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
456 .pci_subdevice = 0x0707,
457 .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */
458 /* other systems */
459 { .pci_subvendor = 0x8384,
460 .pci_subdevice = 0x7680,
461 .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */
462 {} /* terminator */ 593 {} /* terminator */
463}; 594};
464 595
@@ -484,120 +615,72 @@ static unsigned int d965_5st_pin_configs[14] = {
484}; 615};
485 616
486static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { 617static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
487 [STAC_REF] = ref927x_pin_configs, 618 [STAC_D965_REF] = ref927x_pin_configs,
488 [STAC_D965_3ST] = d965_3st_pin_configs, 619 [STAC_D965_3ST] = d965_3st_pin_configs,
489 [STAC_D965_5ST] = d965_5st_pin_configs, 620 [STAC_D965_5ST] = d965_5st_pin_configs,
490}; 621};
491 622
492static struct hda_board_config stac927x_cfg_tbl[] = { 623static const char *stac927x_models[STAC_927X_MODELS] = {
493 { .modelname = "5stack", .config = STAC_D965_5ST }, 624 [STAC_D965_REF] = "ref",
494 { .modelname = "3stack", .config = STAC_D965_3ST }, 625 [STAC_D965_3ST] = "3stack",
495 { .modelname = "ref", 626 [STAC_D965_5ST] = "5stack",
496 .pci_subvendor = PCI_VENDOR_ID_INTEL, 627};
497 .pci_subdevice = 0x2668, /* DFI LanParty */ 628
498 .config = STAC_REF }, /* SigmaTel reference board */ 629static struct snd_pci_quirk stac927x_cfg_tbl[] = {
630 /* SigmaTel reference board */
631 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
632 "DFI LanParty", STAC_D965_REF),
499 /* Intel 946 based systems */ 633 /* Intel 946 based systems */
500 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 634 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
501 .pci_subdevice = 0x3d01, 635 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
502 .config = STAC_D965_3ST }, /* D946 configuration */
503 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
504 .pci_subdevice = 0xa301,
505 .config = STAC_D965_3ST }, /* Intel D946GZT - 3 stack */
506 /* 965 based 3 stack systems */ 636 /* 965 based 3 stack systems */
507 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 637 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
508 .pci_subdevice = 0x2116, 638 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
509 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ 639 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
510 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 640 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
511 .pci_subdevice = 0x2115, 641 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
512 .config = STAC_D965_3ST }, /* Intel DQ965WC - 3 Stack */ 642 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
513 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 643 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
514 .pci_subdevice = 0x2114, 644 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
515 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ 645 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
516 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 646 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
517 .pci_subdevice = 0x2113, 647 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
518 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ 648 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
519 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 649 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
520 .pci_subdevice = 0x2112, 650 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
521 .config = STAC_D965_3ST }, /* Intel DG965MS - 3 Stack */ 651 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
522 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 652 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
523 .pci_subdevice = 0x2111,
524 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
525 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
526 .pci_subdevice = 0x2110,
527 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
528 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
529 .pci_subdevice = 0x2009,
530 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
531 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
532 .pci_subdevice = 0x2008,
533 .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */
534 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
535 .pci_subdevice = 0x2007,
536 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
537 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
538 .pci_subdevice = 0x2006,
539 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
540 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
541 .pci_subdevice = 0x2005,
542 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
543 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
544 .pci_subdevice = 0x2004,
545 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
546 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
547 .pci_subdevice = 0x2003,
548 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
549 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
550 .pci_subdevice = 0x2002,
551 .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
552 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
553 .pci_subdevice = 0x2001,
554 .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */
555 /* 965 based 5 stack systems */ 653 /* 965 based 5 stack systems */
556 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 654 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
557 .pci_subdevice = 0x2301, 655 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
558 .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ 656 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
559 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 657 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
560 .pci_subdevice = 0x2302, 658 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
561 .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ 659 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
562 { .pci_subvendor = PCI_VENDOR_ID_INTEL, 660 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
563 .pci_subdevice = 0x2303, 661 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
564 .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ 662 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
565 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
566 .pci_subdevice = 0x2304,
567 .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
568 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
569 .pci_subdevice = 0x2305,
570 .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
571 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
572 .pci_subdevice = 0x2501,
573 .config = STAC_D965_5ST }, /* Intel DG965MQ - 5 Stack */
574 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
575 .pci_subdevice = 0x2502,
576 .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
577 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
578 .pci_subdevice = 0x2503,
579 .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
580 { .pci_subvendor = PCI_VENDOR_ID_INTEL,
581 .pci_subdevice = 0x2504,
582 .config = STAC_D965_5ST }, /* Intel DQ965GF - 5 Stack */
583 {} /* terminator */ 663 {} /* terminator */
584}; 664};
585 665
586static unsigned int ref9205_pin_configs[12] = { 666static unsigned int ref9205_pin_configs[12] = {
587 0x40000100, 0x40000100, 0x01016011, 0x01014010, 667 0x40000100, 0x40000100, 0x01016011, 0x01014010,
588 0x01813122, 0x01a19021, 0x40000100, 0x40000100, 668 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
589 0x40000100, 0x40000100, 0x01441030, 0x01c41030 669 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
590}; 670};
591 671
592static unsigned int *stac9205_brd_tbl[] = { 672static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
593 ref9205_pin_configs, 673 ref9205_pin_configs,
594}; 674};
595 675
596static struct hda_board_config stac9205_cfg_tbl[] = { 676static const char *stac9205_models[STAC_9205_MODELS] = {
597 { .modelname = "ref", 677 [STAC_9205_REF] = "ref",
598 .pci_subvendor = PCI_VENDOR_ID_INTEL, 678};
599 .pci_subdevice = 0x2668, /* DFI LanParty */ 679
600 .config = STAC_REF }, /* SigmaTel reference board */ 680static struct snd_pci_quirk stac9205_cfg_tbl[] = {
681 /* SigmaTel reference board */
682 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
683 "DFI LanParty", STAC_9205_REF),
601 {} /* terminator */ 684 {} /* terminator */
602}; 685};
603 686
@@ -1154,6 +1237,58 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
1154 return 0; 1237 return 0;
1155} 1238}
1156 1239
1240/* labels for dmic mux inputs */
1241static const char *stac92xx_dmic_labels[5] = {
1242 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
1243 "Digital Mic 3", "Digital Mic 4"
1244};
1245
1246/* create playback/capture controls for input pins on dmic capable codecs */
1247static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
1248 const struct auto_pin_cfg *cfg)
1249{
1250 struct sigmatel_spec *spec = codec->spec;
1251 struct hda_input_mux *dimux = &spec->private_dimux;
1252 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
1253 int i, j;
1254
1255 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
1256 dimux->items[dimux->num_items].index = 0;
1257 dimux->num_items++;
1258
1259 for (i = 0; i < spec->num_dmics; i++) {
1260 int index;
1261 int num_cons;
1262 unsigned int def_conf;
1263
1264 def_conf = snd_hda_codec_read(codec,
1265 spec->dmic_nids[i],
1266 0,
1267 AC_VERB_GET_CONFIG_DEFAULT,
1268 0);
1269 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
1270 continue;
1271
1272 num_cons = snd_hda_get_connections(codec,
1273 spec->dmux_nid,
1274 con_lst,
1275 HDA_MAX_NUM_INPUTS);
1276 for (j = 0; j < num_cons; j++)
1277 if (con_lst[j] == spec->dmic_nids[i]) {
1278 index = j;
1279 goto found;
1280 }
1281 continue;
1282found:
1283 dimux->items[dimux->num_items].label =
1284 stac92xx_dmic_labels[dimux->num_items];
1285 dimux->items[dimux->num_items].index = index;
1286 dimux->num_items++;
1287 }
1288
1289 return 0;
1290}
1291
1157/* create playback/capture controls for input pins */ 1292/* create playback/capture controls for input pins */
1158static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) 1293static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
1159{ 1294{
@@ -1238,7 +1373,9 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
1238 struct sigmatel_spec *spec = codec->spec; 1373 struct sigmatel_spec *spec = codec->spec;
1239 int err; 1374 int err;
1240 1375
1241 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) 1376 if ((err = snd_hda_parse_pin_def_config(codec,
1377 &spec->autocfg,
1378 spec->dmic_nids)) < 0)
1242 return err; 1379 return err;
1243 if (! spec->autocfg.line_outs) 1380 if (! spec->autocfg.line_outs)
1244 return 0; /* can't find valid pin config */ 1381 return 0; /* can't find valid pin config */
@@ -1254,6 +1391,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
1254 (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) 1391 (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
1255 return err; 1392 return err;
1256 1393
1394 if (spec->num_dmics > 0)
1395 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
1396 &spec->autocfg)) < 0)
1397 return err;
1398
1257 spec->multiout.max_channels = spec->multiout.num_dacs * 2; 1399 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1258 if (spec->multiout.max_channels > 2) 1400 if (spec->multiout.max_channels > 2)
1259 spec->surr_switch = 1; 1401 spec->surr_switch = 1;
@@ -1267,6 +1409,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
1267 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 1409 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1268 1410
1269 spec->input_mux = &spec->private_imux; 1411 spec->input_mux = &spec->private_imux;
1412 spec->dinput_mux = &spec->private_dimux;
1270 1413
1271 return 1; 1414 return 1;
1272} 1415}
@@ -1366,6 +1509,7 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
1366 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 1509 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1367 1510
1368 spec->input_mux = &spec->private_imux; 1511 spec->input_mux = &spec->private_imux;
1512 spec->dinput_mux = &spec->private_dimux;
1369 1513
1370 return 1; 1514 return 1;
1371} 1515}
@@ -1448,6 +1592,11 @@ static int stac92xx_init(struct hda_codec *codec)
1448 stac92xx_auto_set_pinctl(codec, nid, pinctl); 1592 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1449 } 1593 }
1450 } 1594 }
1595 if (spec->num_dmics > 0)
1596 for (i = 0; i < spec->num_dmics; i++)
1597 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
1598 AC_PINCTL_IN_EN);
1599
1451 if (cfg->dig_out_pin) 1600 if (cfg->dig_out_pin)
1452 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, 1601 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
1453 AC_PINCTL_OUT_EN); 1602 AC_PINCTL_OUT_EN);
@@ -1598,7 +1747,9 @@ static int patch_stac9200(struct hda_codec *codec)
1598 codec->spec = spec; 1747 codec->spec = spec;
1599 spec->num_pins = 8; 1748 spec->num_pins = 8;
1600 spec->pin_nids = stac9200_pin_nids; 1749 spec->pin_nids = stac9200_pin_nids;
1601 spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl); 1750 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
1751 stac9200_models,
1752 stac9200_cfg_tbl);
1602 if (spec->board_config < 0) { 1753 if (spec->board_config < 0) {
1603 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); 1754 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
1604 err = stac92xx_save_bios_config_regs(codec); 1755 err = stac92xx_save_bios_config_regs(codec);
@@ -1618,6 +1769,7 @@ static int patch_stac9200(struct hda_codec *codec)
1618 spec->adc_nids = stac9200_adc_nids; 1769 spec->adc_nids = stac9200_adc_nids;
1619 spec->mux_nids = stac9200_mux_nids; 1770 spec->mux_nids = stac9200_mux_nids;
1620 spec->num_muxes = 1; 1771 spec->num_muxes = 1;
1772 spec->num_dmics = 0;
1621 1773
1622 spec->init = stac9200_core_init; 1774 spec->init = stac9200_core_init;
1623 spec->mixer = stac9200_mixer; 1775 spec->mixer = stac9200_mixer;
@@ -1633,6 +1785,56 @@ static int patch_stac9200(struct hda_codec *codec)
1633 return 0; 1785 return 0;
1634} 1786}
1635 1787
1788static int patch_stac925x(struct hda_codec *codec)
1789{
1790 struct sigmatel_spec *spec;
1791 int err;
1792
1793 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1794 if (spec == NULL)
1795 return -ENOMEM;
1796
1797 codec->spec = spec;
1798 spec->num_pins = 8;
1799 spec->pin_nids = stac925x_pin_nids;
1800 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
1801 stac925x_models,
1802 stac925x_cfg_tbl);
1803 if (spec->board_config < 0) {
1804 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x, using BIOS defaults\n");
1805 err = stac92xx_save_bios_config_regs(codec);
1806 if (err < 0) {
1807 stac92xx_free(codec);
1808 return err;
1809 }
1810 spec->pin_configs = spec->bios_pin_configs;
1811 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
1812 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
1813 stac92xx_set_config_regs(codec);
1814 }
1815
1816 spec->multiout.max_channels = 2;
1817 spec->multiout.num_dacs = 1;
1818 spec->multiout.dac_nids = stac925x_dac_nids;
1819 spec->adc_nids = stac925x_adc_nids;
1820 spec->mux_nids = stac925x_mux_nids;
1821 spec->num_muxes = 1;
1822 spec->num_dmics = 0;
1823
1824 spec->init = stac925x_core_init;
1825 spec->mixer = stac925x_mixer;
1826
1827 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
1828 if (err < 0) {
1829 stac92xx_free(codec);
1830 return err;
1831 }
1832
1833 codec->patch_ops = stac92xx_patch_ops;
1834
1835 return 0;
1836}
1837
1636static int patch_stac922x(struct hda_codec *codec) 1838static int patch_stac922x(struct hda_codec *codec)
1637{ 1839{
1638 struct sigmatel_spec *spec; 1840 struct sigmatel_spec *spec;
@@ -1645,7 +1847,9 @@ static int patch_stac922x(struct hda_codec *codec)
1645 codec->spec = spec; 1847 codec->spec = spec;
1646 spec->num_pins = 10; 1848 spec->num_pins = 10;
1647 spec->pin_nids = stac922x_pin_nids; 1849 spec->pin_nids = stac922x_pin_nids;
1648 spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); 1850 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
1851 stac922x_models,
1852 stac922x_cfg_tbl);
1649 if (spec->board_config < 0) { 1853 if (spec->board_config < 0) {
1650 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " 1854 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
1651 "using BIOS defaults\n"); 1855 "using BIOS defaults\n");
@@ -1663,6 +1867,7 @@ static int patch_stac922x(struct hda_codec *codec)
1663 spec->adc_nids = stac922x_adc_nids; 1867 spec->adc_nids = stac922x_adc_nids;
1664 spec->mux_nids = stac922x_mux_nids; 1868 spec->mux_nids = stac922x_mux_nids;
1665 spec->num_muxes = 2; 1869 spec->num_muxes = 2;
1870 spec->num_dmics = 0;
1666 1871
1667 spec->init = stac922x_core_init; 1872 spec->init = stac922x_core_init;
1668 spec->mixer = stac922x_mixer; 1873 spec->mixer = stac922x_mixer;
@@ -1695,7 +1900,9 @@ static int patch_stac927x(struct hda_codec *codec)
1695 codec->spec = spec; 1900 codec->spec = spec;
1696 spec->num_pins = 14; 1901 spec->num_pins = 14;
1697 spec->pin_nids = stac927x_pin_nids; 1902 spec->pin_nids = stac927x_pin_nids;
1698 spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl); 1903 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
1904 stac927x_models,
1905 stac927x_cfg_tbl);
1699 if (spec->board_config < 0) { 1906 if (spec->board_config < 0) {
1700 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); 1907 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
1701 err = stac92xx_save_bios_config_regs(codec); 1908 err = stac92xx_save_bios_config_regs(codec);
@@ -1714,6 +1921,7 @@ static int patch_stac927x(struct hda_codec *codec)
1714 spec->adc_nids = stac927x_adc_nids; 1921 spec->adc_nids = stac927x_adc_nids;
1715 spec->mux_nids = stac927x_mux_nids; 1922 spec->mux_nids = stac927x_mux_nids;
1716 spec->num_muxes = 3; 1923 spec->num_muxes = 3;
1924 spec->num_dmics = 0;
1717 spec->init = d965_core_init; 1925 spec->init = d965_core_init;
1718 spec->mixer = stac9227_mixer; 1926 spec->mixer = stac9227_mixer;
1719 break; 1927 break;
@@ -1721,6 +1929,7 @@ static int patch_stac927x(struct hda_codec *codec)
1721 spec->adc_nids = stac927x_adc_nids; 1929 spec->adc_nids = stac927x_adc_nids;
1722 spec->mux_nids = stac927x_mux_nids; 1930 spec->mux_nids = stac927x_mux_nids;
1723 spec->num_muxes = 3; 1931 spec->num_muxes = 3;
1932 spec->num_dmics = 0;
1724 spec->init = d965_core_init; 1933 spec->init = d965_core_init;
1725 spec->mixer = stac9227_mixer; 1934 spec->mixer = stac9227_mixer;
1726 break; 1935 break;
@@ -1728,6 +1937,7 @@ static int patch_stac927x(struct hda_codec *codec)
1728 spec->adc_nids = stac927x_adc_nids; 1937 spec->adc_nids = stac927x_adc_nids;
1729 spec->mux_nids = stac927x_mux_nids; 1938 spec->mux_nids = stac927x_mux_nids;
1730 spec->num_muxes = 3; 1939 spec->num_muxes = 3;
1940 spec->num_dmics = 0;
1731 spec->init = stac927x_core_init; 1941 spec->init = stac927x_core_init;
1732 spec->mixer = stac927x_mixer; 1942 spec->mixer = stac927x_mixer;
1733 } 1943 }
@@ -1757,7 +1967,9 @@ static int patch_stac9205(struct hda_codec *codec)
1757 codec->spec = spec; 1967 codec->spec = spec;
1758 spec->num_pins = 14; 1968 spec->num_pins = 14;
1759 spec->pin_nids = stac9205_pin_nids; 1969 spec->pin_nids = stac9205_pin_nids;
1760 spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl); 1970 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
1971 stac9205_models,
1972 stac9205_cfg_tbl);
1761 if (spec->board_config < 0) { 1973 if (spec->board_config < 0) {
1762 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); 1974 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
1763 err = stac92xx_save_bios_config_regs(codec); 1975 err = stac92xx_save_bios_config_regs(codec);
@@ -1773,13 +1985,28 @@ static int patch_stac9205(struct hda_codec *codec)
1773 1985
1774 spec->adc_nids = stac9205_adc_nids; 1986 spec->adc_nids = stac9205_adc_nids;
1775 spec->mux_nids = stac9205_mux_nids; 1987 spec->mux_nids = stac9205_mux_nids;
1776 spec->num_muxes = 3; 1988 spec->num_muxes = 2;
1989 spec->dmic_nids = stac9205_dmic_nids;
1990 spec->num_dmics = 2;
1991 spec->dmux_nid = 0x1d;
1777 1992
1778 spec->init = stac9205_core_init; 1993 spec->init = stac9205_core_init;
1779 spec->mixer = stac9205_mixer; 1994 spec->mixer = stac9205_mixer;
1780 1995
1781 spec->multiout.dac_nids = spec->dac_nids; 1996 spec->multiout.dac_nids = spec->dac_nids;
1782 1997
1998 /* Configure GPIO0 as EAPD output */
1999 snd_hda_codec_write(codec, codec->afg, 0,
2000 AC_VERB_SET_GPIO_DIRECTION, 0x00000001);
2001 /* Configure GPIO0 as CMOS */
2002 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
2003 /* Assert GPIO0 high */
2004 snd_hda_codec_write(codec, codec->afg, 0,
2005 AC_VERB_SET_GPIO_DATA, 0x00000001);
2006 /* Enable GPIO0 */
2007 snd_hda_codec_write(codec, codec->afg, 0,
2008 AC_VERB_SET_GPIO_MASK, 0x00000001);
2009
1783 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); 2010 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
1784 if (err < 0) { 2011 if (err < 0) {
1785 stac92xx_free(codec); 2012 stac92xx_free(codec);
@@ -1963,18 +2190,19 @@ enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
1963 /* Unknown. id=0x83847661 and subsys=0x104D1200. */ 2190 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
1964 STAC9872K_VAIO, 2191 STAC9872K_VAIO,
1965 /* AR Series. id=0x83847664 and subsys=104D1300 */ 2192 /* AR Series. id=0x83847664 and subsys=104D1300 */
1966 CXD9872AKD_VAIO 2193 CXD9872AKD_VAIO,
1967 }; 2194 STAC_9872_MODELS,
1968 2195};
1969static struct hda_board_config stac9872_cfg_tbl[] = { 2196
1970 { .modelname = "vaio", .config = CXD9872RD_VAIO }, 2197static const char *stac9872_models[STAC_9872_MODELS] = {
1971 { .modelname = "vaio-ar", .config = CXD9872AKD_VAIO }, 2198 [CXD9872RD_VAIO] = "vaio",
1972 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6, 2199 [CXD9872AKD_VAIO] = "vaio-ar",
1973 .config = CXD9872RD_VAIO }, 2200};
1974 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef, 2201
1975 .config = CXD9872RD_VAIO }, 2202static struct snd_pci_quirk stac9872_cfg_tbl[] = {
1976 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81fd, 2203 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
1977 .config = CXD9872AKD_VAIO }, 2204 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
2205 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
1978 {} 2206 {}
1979}; 2207};
1980 2208
@@ -1983,7 +2211,9 @@ static int patch_stac9872(struct hda_codec *codec)
1983 struct sigmatel_spec *spec; 2211 struct sigmatel_spec *spec;
1984 int board_config; 2212 int board_config;
1985 2213
1986 board_config = snd_hda_check_board_config(codec, stac9872_cfg_tbl); 2214 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
2215 stac9872_models,
2216 stac9872_cfg_tbl);
1987 if (board_config < 0) 2217 if (board_config < 0)
1988 /* unknown config, let generic-parser do its job... */ 2218 /* unknown config, let generic-parser do its job... */
1989 return snd_hda_parse_generic_codec(codec); 2219 return snd_hda_parse_generic_codec(codec);
@@ -2055,6 +2285,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
2055 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, 2285 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
2056 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, 2286 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
2057 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, 2287 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
2288 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
2289 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
2290 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
2291 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
2292 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
2293 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
2058 /* The following does not take into account .id=0x83847661 when subsys = 2294 /* The following does not take into account .id=0x83847661 when subsys =
2059 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are 2295 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
2060 * currently not fully supported. 2296 * currently not fully supported.
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
new file mode 100644
index 000000000000..4c839b031729
--- /dev/null
+++ b/sound/pci/hda/patch_via.c
@@ -0,0 +1,1396 @@
1/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for VIA VT1708 codec
5 *
6 * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com>
7 * Takashi Iwai <tiwai@suse.de>
8 *
9 * This driver is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This driver is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
25/* */
26/* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */
27/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */
28/* 2006-08-02 Lydia Wang Add support to VT1709 codec */
29/* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */
30/* */
31/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32
33
34#include <sound/driver.h>
35#include <linux/init.h>
36#include <linux/delay.h>
37#include <linux/slab.h>
38#include <linux/pci.h>
39#include <sound/core.h>
40#include "hda_codec.h"
41#include "hda_local.h"
42
43
44/* amp values */
45#define AMP_VAL_IDX_SHIFT 19
46#define AMP_VAL_IDX_MASK (0x0f<<19)
47
48#define NUM_CONTROL_ALLOC 32
49#define NUM_VERB_ALLOC 32
50
51/* Pin Widget NID */
52#define VT1708_HP_NID 0x13
53#define VT1708_DIGOUT_NID 0x14
54#define VT1708_DIGIN_NID 0x16
55
56#define VT1709_HP_DAC_NID 0x28
57#define VT1709_DIGOUT_NID 0x13
58#define VT1709_DIGIN_NID 0x17
59
60#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
61#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
62#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
63
64
65enum {
66 VIA_CTL_WIDGET_VOL,
67 VIA_CTL_WIDGET_MUTE,
68};
69
70enum {
71 AUTO_SEQ_FRONT,
72 AUTO_SEQ_SURROUND,
73 AUTO_SEQ_CENLFE,
74 AUTO_SEQ_SIDE
75};
76
77static struct snd_kcontrol_new vt1708_control_templates[] = {
78 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
79 HDA_CODEC_MUTE(NULL, 0, 0, 0),
80};
81
82
83struct via_spec {
84 /* codec parameterization */
85 struct snd_kcontrol_new *mixers[3];
86 unsigned int num_mixers;
87
88 struct hda_verb *init_verbs;
89
90 char *stream_name_analog;
91 struct hda_pcm_stream *stream_analog_playback;
92 struct hda_pcm_stream *stream_analog_capture;
93
94 char *stream_name_digital;
95 struct hda_pcm_stream *stream_digital_playback;
96 struct hda_pcm_stream *stream_digital_capture;
97
98 /* playback */
99 struct hda_multi_out multiout;
100
101 /* capture */
102 unsigned int num_adc_nids;
103 hda_nid_t *adc_nids;
104 hda_nid_t dig_in_nid;
105
106 /* capture source */
107 const struct hda_input_mux *input_mux;
108 unsigned int cur_mux[3];
109
110 /* PCM information */
111 struct hda_pcm pcm_rec[2];
112
113 /* dynamic controls, init_verbs and input_mux */
114 struct auto_pin_cfg autocfg;
115 unsigned int num_kctl_alloc, num_kctl_used;
116 struct snd_kcontrol_new *kctl_alloc;
117 struct hda_input_mux private_imux;
118 hda_nid_t private_dac_nids[4];
119};
120
121static hda_nid_t vt1708_adc_nids[2] = {
122 /* ADC1-2 */
123 0x15, 0x27
124};
125
126static hda_nid_t vt1709_adc_nids[3] = {
127 /* ADC1-2 */
128 0x14, 0x15, 0x16
129};
130
131/* add dynamic controls */
132static int via_add_control(struct via_spec *spec, int type, const char *name,
133 unsigned long val)
134{
135 struct snd_kcontrol_new *knew;
136
137 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
138 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
139
140 /* array + terminator */
141 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
142 if (!knew)
143 return -ENOMEM;
144 if (spec->kctl_alloc) {
145 memcpy(knew, spec->kctl_alloc,
146 sizeof(*knew) * spec->num_kctl_alloc);
147 kfree(spec->kctl_alloc);
148 }
149 spec->kctl_alloc = knew;
150 spec->num_kctl_alloc = num;
151 }
152
153 knew = &spec->kctl_alloc[spec->num_kctl_used];
154 *knew = vt1708_control_templates[type];
155 knew->name = kstrdup(name, GFP_KERNEL);
156
157 if (!knew->name)
158 return -ENOMEM;
159 knew->private_value = val;
160 spec->num_kctl_used++;
161 return 0;
162}
163
164/* create input playback/capture controls for the given pin */
165static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
166 const char *ctlname, int idx, int mix_nid)
167{
168 char name[32];
169 int err;
170
171 sprintf(name, "%s Playback Volume", ctlname);
172 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
173 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
174 if (err < 0)
175 return err;
176 sprintf(name, "%s Playback Switch", ctlname);
177 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
178 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
179 if (err < 0)
180 return err;
181 return 0;
182}
183
184static void via_auto_set_output_and_unmute(struct hda_codec *codec,
185 hda_nid_t nid, int pin_type,
186 int dac_idx)
187{
188 /* set as output */
189 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
190 pin_type);
191 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
192 AMP_OUT_UNMUTE);
193}
194
195
196static void via_auto_init_multi_out(struct hda_codec *codec)
197{
198 struct via_spec *spec = codec->spec;
199 int i;
200
201 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
202 hda_nid_t nid = spec->autocfg.line_out_pins[i];
203 if (nid)
204 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
205 }
206}
207
208static void via_auto_init_hp_out(struct hda_codec *codec)
209{
210 struct via_spec *spec = codec->spec;
211 hda_nid_t pin;
212
213 pin = spec->autocfg.hp_pins[0];
214 if (pin) /* connect to front */
215 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
216}
217
218static void via_auto_init_analog_input(struct hda_codec *codec)
219{
220 struct via_spec *spec = codec->spec;
221 int i;
222
223 for (i = 0; i < AUTO_PIN_LAST; i++) {
224 hda_nid_t nid = spec->autocfg.input_pins[i];
225
226 snd_hda_codec_write(codec, nid, 0,
227 AC_VERB_SET_PIN_WIDGET_CONTROL,
228 (i <= AUTO_PIN_FRONT_MIC ?
229 PIN_VREF50 : PIN_IN));
230
231 }
232}
233/*
234 * input MUX handling
235 */
236static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
237 struct snd_ctl_elem_info *uinfo)
238{
239 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
240 struct via_spec *spec = codec->spec;
241 return snd_hda_input_mux_info(spec->input_mux, uinfo);
242}
243
244static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
245 struct snd_ctl_elem_value *ucontrol)
246{
247 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
248 struct via_spec *spec = codec->spec;
249 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
250
251 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
252 return 0;
253}
254
255static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
256 struct snd_ctl_elem_value *ucontrol)
257{
258 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
259 struct via_spec *spec = codec->spec;
260 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
261 unsigned int vendor_id = codec->vendor_id;
262
263 /* AIW0 lydia 060801 add for correct sw0 input select */
264 if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
265 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
266 0x18, &spec->cur_mux[adc_idx]);
267 else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
268 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) )
269 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
270 0x19, &spec->cur_mux[adc_idx]);
271 else
272 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
273 spec->adc_nids[adc_idx],
274 &spec->cur_mux[adc_idx]);
275}
276
277/* capture mixer elements */
278static struct snd_kcontrol_new vt1708_capture_mixer[] = {
279 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
280 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
281 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
282 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
283 {
284 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
285 /* The multiple "Capture Source" controls confuse alsamixer
286 * So call somewhat different..
287 * FIXME: the controls appear in the "playback" view!
288 */
289 /* .name = "Capture Source", */
290 .name = "Input Source",
291 .count = 1,
292 .info = via_mux_enum_info,
293 .get = via_mux_enum_get,
294 .put = via_mux_enum_put,
295 },
296 { } /* end */
297};
298/*
299 * generic initialization of ADC, input mixers and output mixers
300 */
301static struct hda_verb vt1708_volume_init_verbs[] = {
302 /*
303 * Unmute ADC0-1 and set the default input to mic-in
304 */
305 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
306 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
307
308
309 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
310 * mixer widget
311 */
312 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
313 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
314 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
315 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
316 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
317 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
318
319 /*
320 * Set up output mixers (0x19 - 0x1b)
321 */
322 /* set vol=0 to output mixers */
323 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
324 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
325 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
326
327 /* Setup default input to PW4 */
328 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
329 /* Set mic as default input of sw0 */
330 {0x18, AC_VERB_SET_CONNECT_SEL, 0x2},
331 /* PW9 Output enable */
332 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
333};
334
335static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
336 struct hda_codec *codec,
337 struct snd_pcm_substream *substream)
338{
339 struct via_spec *spec = codec->spec;
340 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
341}
342
343static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
344 struct hda_codec *codec,
345 unsigned int stream_tag,
346 unsigned int format,
347 struct snd_pcm_substream *substream)
348{
349 struct via_spec *spec = codec->spec;
350 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
351 stream_tag, format, substream);
352}
353
354static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
355 struct hda_codec *codec,
356 struct snd_pcm_substream *substream)
357{
358 struct via_spec *spec = codec->spec;
359 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
360}
361
362/*
363 * Digital out
364 */
365static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
366 struct hda_codec *codec,
367 struct snd_pcm_substream *substream)
368{
369 struct via_spec *spec = codec->spec;
370 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
371}
372
373static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
374 struct hda_codec *codec,
375 struct snd_pcm_substream *substream)
376{
377 struct via_spec *spec = codec->spec;
378 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
379}
380
381/*
382 * Analog capture
383 */
384static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
385 struct hda_codec *codec,
386 unsigned int stream_tag,
387 unsigned int format,
388 struct snd_pcm_substream *substream)
389{
390 struct via_spec *spec = codec->spec;
391
392 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
393 stream_tag, 0, format);
394 return 0;
395}
396
397static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
398 struct hda_codec *codec,
399 struct snd_pcm_substream *substream)
400{
401 struct via_spec *spec = codec->spec;
402 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
403 0, 0, 0);
404 return 0;
405}
406
407static struct hda_pcm_stream vt1708_pcm_analog_playback = {
408 .substreams = 1,
409 .channels_min = 2,
410 .channels_max = 8,
411 .nid = 0x10, /* NID to query formats and rates */
412 .ops = {
413 .open = via_playback_pcm_open,
414 .prepare = via_playback_pcm_prepare,
415 .cleanup = via_playback_pcm_cleanup
416 },
417};
418
419static struct hda_pcm_stream vt1708_pcm_analog_capture = {
420 .substreams = 2,
421 .channels_min = 2,
422 .channels_max = 2,
423 .nid = 0x15, /* NID to query formats and rates */
424 .ops = {
425 .prepare = via_capture_pcm_prepare,
426 .cleanup = via_capture_pcm_cleanup
427 },
428};
429
430static struct hda_pcm_stream vt1708_pcm_digital_playback = {
431 .substreams = 1,
432 .channels_min = 2,
433 .channels_max = 2,
434 /* NID is set in via_build_pcms */
435 .ops = {
436 .open = via_dig_playback_pcm_open,
437 .close = via_dig_playback_pcm_close
438 },
439};
440
441static struct hda_pcm_stream vt1708_pcm_digital_capture = {
442 .substreams = 1,
443 .channels_min = 2,
444 .channels_max = 2,
445};
446
447static int via_build_controls(struct hda_codec *codec)
448{
449 struct via_spec *spec = codec->spec;
450 int err;
451 int i;
452
453 for (i = 0; i < spec->num_mixers; i++) {
454 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
455 if (err < 0)
456 return err;
457 }
458
459 if (spec->multiout.dig_out_nid) {
460 err = snd_hda_create_spdif_out_ctls(codec,
461 spec->multiout.dig_out_nid);
462 if (err < 0)
463 return err;
464 }
465 if (spec->dig_in_nid) {
466 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
467 if (err < 0)
468 return err;
469 }
470 return 0;
471}
472
473static int via_build_pcms(struct hda_codec *codec)
474{
475 struct via_spec *spec = codec->spec;
476 struct hda_pcm *info = spec->pcm_rec;
477
478 codec->num_pcms = 1;
479 codec->pcm_info = info;
480
481 info->name = spec->stream_name_analog;
482 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
483 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
484 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
485 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
486
487 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
488 spec->multiout.max_channels;
489
490 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
491 codec->num_pcms++;
492 info++;
493 info->name = spec->stream_name_digital;
494 if (spec->multiout.dig_out_nid) {
495 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
496 *(spec->stream_digital_playback);
497 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
498 spec->multiout.dig_out_nid;
499 }
500 if (spec->dig_in_nid) {
501 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
502 *(spec->stream_digital_capture);
503 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
504 spec->dig_in_nid;
505 }
506 }
507
508 return 0;
509}
510
511static void via_free(struct hda_codec *codec)
512{
513 struct via_spec *spec = codec->spec;
514 unsigned int i;
515
516 if (!spec)
517 return;
518
519 if (spec->kctl_alloc) {
520 for (i = 0; i < spec->num_kctl_used; i++)
521 kfree(spec->kctl_alloc[i].name);
522 kfree(spec->kctl_alloc);
523 }
524
525 kfree(codec->spec);
526}
527
528static int via_init(struct hda_codec *codec)
529{
530 struct via_spec *spec = codec->spec;
531 snd_hda_sequence_write(codec, spec->init_verbs);
532 return 0;
533}
534
535#ifdef CONFIG_PM
536/*
537 * resume
538 */
539static int via_resume(struct hda_codec *codec)
540{
541 struct via_spec *spec = codec->spec;
542 int i;
543
544 via_init(codec);
545 for (i = 0; i < spec->num_mixers; i++)
546 snd_hda_resume_ctls(codec, spec->mixers[i]);
547 if (spec->multiout.dig_out_nid)
548 snd_hda_resume_spdif_out(codec);
549 if (spec->dig_in_nid)
550 snd_hda_resume_spdif_in(codec);
551
552 return 0;
553}
554#endif
555
556/*
557 */
558static struct hda_codec_ops via_patch_ops = {
559 .build_controls = via_build_controls,
560 .build_pcms = via_build_pcms,
561 .init = via_init,
562 .free = via_free,
563#ifdef CONFIG_PM
564 .resume = via_resume,
565#endif
566};
567
568/* fill in the dac_nids table from the parsed pin configuration */
569static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
570 const struct auto_pin_cfg *cfg)
571{
572 int i;
573 hda_nid_t nid;
574
575 spec->multiout.num_dacs = cfg->line_outs;
576
577 spec->multiout.dac_nids = spec->private_dac_nids;
578
579 for(i = 0; i < 4; i++) {
580 nid = cfg->line_out_pins[i];
581 if (nid) {
582 /* config dac list */
583 switch (i) {
584 case AUTO_SEQ_FRONT:
585 spec->multiout.dac_nids[i] = 0x10;
586 break;
587 case AUTO_SEQ_CENLFE:
588 spec->multiout.dac_nids[i] = 0x12;
589 break;
590 case AUTO_SEQ_SURROUND:
591 spec->multiout.dac_nids[i] = 0x13;
592 break;
593 case AUTO_SEQ_SIDE:
594 spec->multiout.dac_nids[i] = 0x11;
595 break;
596 }
597 }
598 }
599
600 return 0;
601}
602
603/* add playback controls from the parsed DAC table */
604static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
605 const struct auto_pin_cfg *cfg)
606{
607 char name[32];
608 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
609 hda_nid_t nid, nid_vol = 0;
610 int i, err;
611
612 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
613 nid = cfg->line_out_pins[i];
614
615 if (!nid)
616 continue;
617
618 if (i != AUTO_SEQ_FRONT)
619 nid_vol = 0x1b - i + 1;
620
621 if (i == AUTO_SEQ_CENLFE) {
622 /* Center/LFE */
623 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
624 "Center Playback Volume",
625 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
626 if (err < 0)
627 return err;
628 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
629 "LFE Playback Volume",
630 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
631 if (err < 0)
632 return err;
633 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
634 "Center Playback Switch",
635 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
636 if (err < 0)
637 return err;
638 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
639 "LFE Playback Switch",
640 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
641 if (err < 0)
642 return err;
643 } else if (i == AUTO_SEQ_FRONT){
644 /* add control to mixer index 0 */
645 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
646 "Master Front Playback Volume",
647 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
648 if (err < 0)
649 return err;
650 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
651 "Master Front Playback Switch",
652 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
653 if (err < 0)
654 return err;
655
656 /* add control to PW3 */
657 sprintf(name, "%s Playback Volume", chname[i]);
658 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
659 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
660 if (err < 0)
661 return err;
662 sprintf(name, "%s Playback Switch", chname[i]);
663 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
664 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
665 if (err < 0)
666 return err;
667 } else {
668 sprintf(name, "%s Playback Volume", chname[i]);
669 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
670 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
671 if (err < 0)
672 return err;
673 sprintf(name, "%s Playback Switch", chname[i]);
674 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
675 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
676 if (err < 0)
677 return err;
678 }
679 }
680
681 return 0;
682}
683
684static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
685{
686 int err;
687
688 if (!pin)
689 return 0;
690
691 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
692
693 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
694 "Headphone Playback Volume",
695 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
696 if (err < 0)
697 return err;
698 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
699 "Headphone Playback Switch",
700 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
701 if (err < 0)
702 return err;
703
704 return 0;
705}
706
707/* create playback/capture controls for input pins */
708static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
709 const struct auto_pin_cfg *cfg)
710{
711 static char *labels[] = {
712 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
713 };
714 struct hda_input_mux *imux = &spec->private_imux;
715 int i, err, idx = 0;
716
717 /* for internal loopback recording select */
718 imux->items[imux->num_items].label = "Stereo Mixer";
719 imux->items[imux->num_items].index = idx;
720 imux->num_items++;
721
722 for (i = 0; i < AUTO_PIN_LAST; i++) {
723 if (!cfg->input_pins[i])
724 continue;
725
726 switch (cfg->input_pins[i]) {
727 case 0x1d: /* Mic */
728 idx = 2;
729 break;
730
731 case 0x1e: /* Line In */
732 idx = 3;
733 break;
734
735 case 0x21: /* Front Mic */
736 idx = 4;
737 break;
738
739 case 0x24: /* CD */
740 idx = 1;
741 break;
742 }
743 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
744 idx, 0x17);
745 if (err < 0)
746 return err;
747 imux->items[imux->num_items].label = labels[i];
748 imux->items[imux->num_items].index = idx;
749 imux->num_items++;
750 }
751 return 0;
752}
753
754static int vt1708_parse_auto_config(struct hda_codec *codec)
755{
756 struct via_spec *spec = codec->spec;
757 int err;
758
759 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
760 if (err < 0)
761 return err;
762 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
763 if (err < 0)
764 return err;
765 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
766 return 0; /* can't find valid BIOS pin config */
767
768 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
769 if (err < 0)
770 return err;
771 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
772 if (err < 0)
773 return err;
774 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
775 if (err < 0)
776 return err;
777
778 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
779
780 if (spec->autocfg.dig_out_pin)
781 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
782 if (spec->autocfg.dig_in_pin)
783 spec->dig_in_nid = VT1708_DIGIN_NID;
784
785 if (spec->kctl_alloc)
786 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
787
788 spec->init_verbs = vt1708_volume_init_verbs;
789
790 spec->input_mux = &spec->private_imux;
791
792 return 1;
793}
794
795/* init callback for auto-configuration model -- overriding the default init */
796static int via_auto_init(struct hda_codec *codec)
797{
798 via_init(codec);
799 via_auto_init_multi_out(codec);
800 via_auto_init_hp_out(codec);
801 via_auto_init_analog_input(codec);
802 return 0;
803}
804
805static int patch_vt1708(struct hda_codec *codec)
806{
807 struct via_spec *spec;
808 int err;
809
810 /* create a codec specific record */
811 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
812 if (spec == NULL)
813 return -ENOMEM;
814
815 codec->spec = spec;
816
817 /* automatic parse from the BIOS config */
818 err = vt1708_parse_auto_config(codec);
819 if (err < 0) {
820 via_free(codec);
821 return err;
822 } else if (!err) {
823 printk(KERN_INFO "hda_codec: Cannot set up configuration "
824 "from BIOS. Using genenic mode...\n");
825 }
826
827
828 spec->stream_name_analog = "VT1708 Analog";
829 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
830 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
831
832 spec->stream_name_digital = "VT1708 Digital";
833 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
834 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
835
836
837 if (!spec->adc_nids && spec->input_mux) {
838 spec->adc_nids = vt1708_adc_nids;
839 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
840 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
841 spec->num_mixers++;
842 }
843
844 codec->patch_ops = via_patch_ops;
845
846 codec->patch_ops.init = via_auto_init;
847
848 return 0;
849}
850
851/* capture mixer elements */
852static struct snd_kcontrol_new vt1709_capture_mixer[] = {
853 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
854 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
855 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
856 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
857 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
858 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
859 {
860 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
861 /* The multiple "Capture Source" controls confuse alsamixer
862 * So call somewhat different..
863 * FIXME: the controls appear in the "playback" view!
864 */
865 /* .name = "Capture Source", */
866 .name = "Input Source",
867 .count = 1,
868 .info = via_mux_enum_info,
869 .get = via_mux_enum_get,
870 .put = via_mux_enum_put,
871 },
872 { } /* end */
873};
874
875/*
876 * generic initialization of ADC, input mixers and output mixers
877 */
878static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
879 /*
880 * Unmute ADC0-2 and set the default input to mic-in
881 */
882 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
883 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
884 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
885
886
887 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
888 * mixer widget
889 */
890 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
891 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
892 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
893 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
894 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
895 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
896
897 /*
898 * Set up output selector (0x1a, 0x1b, 0x29)
899 */
900 /* set vol=0 to output mixers */
901 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
902 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
903 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
904
905 /*
906 * Unmute PW3 and PW4
907 */
908 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
909 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
910
911 /* Set input of PW4 as AOW4 */
912 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
913 /* Set mic as default input of sw0 */
914 {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
915 /* PW9 Output enable */
916 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
917 { }
918};
919
920static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
921 .substreams = 1,
922 .channels_min = 2,
923 .channels_max = 10,
924 .nid = 0x10, /* NID to query formats and rates */
925 .ops = {
926 .open = via_playback_pcm_open,
927 .prepare = via_playback_pcm_prepare,
928 .cleanup = via_playback_pcm_cleanup
929 },
930};
931
932static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
933 .substreams = 1,
934 .channels_min = 2,
935 .channels_max = 6,
936 .nid = 0x10, /* NID to query formats and rates */
937 .ops = {
938 .open = via_playback_pcm_open,
939 .prepare = via_playback_pcm_prepare,
940 .cleanup = via_playback_pcm_cleanup
941 },
942};
943
944static struct hda_pcm_stream vt1709_pcm_analog_capture = {
945 .substreams = 2,
946 .channels_min = 2,
947 .channels_max = 2,
948 .nid = 0x14, /* NID to query formats and rates */
949 .ops = {
950 .prepare = via_capture_pcm_prepare,
951 .cleanup = via_capture_pcm_cleanup
952 },
953};
954
955static struct hda_pcm_stream vt1709_pcm_digital_playback = {
956 .substreams = 1,
957 .channels_min = 2,
958 .channels_max = 2,
959 /* NID is set in via_build_pcms */
960 .ops = {
961 .open = via_dig_playback_pcm_open,
962 .close = via_dig_playback_pcm_close
963 },
964};
965
966static struct hda_pcm_stream vt1709_pcm_digital_capture = {
967 .substreams = 1,
968 .channels_min = 2,
969 .channels_max = 2,
970};
971
972static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
973 const struct auto_pin_cfg *cfg)
974{
975 int i;
976 hda_nid_t nid;
977
978 if (cfg->line_outs == 4) /* 10 channels */
979 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
980 else if (cfg->line_outs == 3) /* 6 channels */
981 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
982
983 spec->multiout.dac_nids = spec->private_dac_nids;
984
985 if (cfg->line_outs == 4) { /* 10 channels */
986 for (i = 0; i < cfg->line_outs; i++) {
987 nid = cfg->line_out_pins[i];
988 if (nid) {
989 /* config dac list */
990 switch (i) {
991 case AUTO_SEQ_FRONT:
992 /* AOW0 */
993 spec->multiout.dac_nids[i] = 0x10;
994 break;
995 case AUTO_SEQ_CENLFE:
996 /* AOW2 */
997 spec->multiout.dac_nids[i] = 0x12;
998 break;
999 case AUTO_SEQ_SURROUND:
1000 /* AOW3 */
1001 spec->multiout.dac_nids[i] = 0x27;
1002 break;
1003 case AUTO_SEQ_SIDE:
1004 /* AOW1 */
1005 spec->multiout.dac_nids[i] = 0x11;
1006 break;
1007 default:
1008 break;
1009 }
1010 }
1011 }
1012 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1013
1014 } else if (cfg->line_outs == 3) { /* 6 channels */
1015 for(i = 0; i < cfg->line_outs; i++) {
1016 nid = cfg->line_out_pins[i];
1017 if (nid) {
1018 /* config dac list */
1019 switch(i) {
1020 case AUTO_SEQ_FRONT:
1021 /* AOW0 */
1022 spec->multiout.dac_nids[i] = 0x10;
1023 break;
1024 case AUTO_SEQ_CENLFE:
1025 /* AOW2 */
1026 spec->multiout.dac_nids[i] = 0x12;
1027 break;
1028 case AUTO_SEQ_SURROUND:
1029 /* AOW1 */
1030 spec->multiout.dac_nids[i] = 0x11;
1031 break;
1032 default:
1033 break;
1034 }
1035 }
1036 }
1037 }
1038
1039 return 0;
1040}
1041
1042/* add playback controls from the parsed DAC table */
1043static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1044 const struct auto_pin_cfg *cfg)
1045{
1046 char name[32];
1047 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1048 hda_nid_t nid = 0;
1049 int i, err;
1050
1051 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1052 nid = cfg->line_out_pins[i];
1053
1054 if (!nid)
1055 continue;
1056
1057 if (i == AUTO_SEQ_CENLFE) {
1058 /* Center/LFE */
1059 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1060 "Center Playback Volume",
1061 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
1062 if (err < 0)
1063 return err;
1064 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1065 "LFE Playback Volume",
1066 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
1067 if (err < 0)
1068 return err;
1069 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1070 "Center Playback Switch",
1071 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
1072 if (err < 0)
1073 return err;
1074 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1075 "LFE Playback Switch",
1076 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
1077 if (err < 0)
1078 return err;
1079 } else if (i == AUTO_SEQ_FRONT){
1080 /* add control to mixer index 0 */
1081 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1082 "Master Front Playback Volume",
1083 HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
1084 if (err < 0)
1085 return err;
1086 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1087 "Master Front Playback Switch",
1088 HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
1089 if (err < 0)
1090 return err;
1091
1092 /* add control to PW3 */
1093 sprintf(name, "%s Playback Volume", chname[i]);
1094 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1095 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
1096 if (err < 0)
1097 return err;
1098 sprintf(name, "%s Playback Switch", chname[i]);
1099 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1100 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
1101 if (err < 0)
1102 return err;
1103 } else if (i == AUTO_SEQ_SURROUND) {
1104 sprintf(name, "%s Playback Volume", chname[i]);
1105 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1106 HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
1107 if (err < 0)
1108 return err;
1109 sprintf(name, "%s Playback Switch", chname[i]);
1110 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1111 HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
1112 if (err < 0)
1113 return err;
1114 } else if (i == AUTO_SEQ_SIDE) {
1115 sprintf(name, "%s Playback Volume", chname[i]);
1116 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1117 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
1118 if (err < 0)
1119 return err;
1120 sprintf(name, "%s Playback Switch", chname[i]);
1121 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1122 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
1123 if (err < 0)
1124 return err;
1125 }
1126 }
1127
1128 return 0;
1129}
1130
1131static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1132{
1133 int err;
1134
1135 if (!pin)
1136 return 0;
1137
1138 if (spec->multiout.num_dacs == 5) /* 10 channels */
1139 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1140 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1141 spec->multiout.hp_nid = 0;
1142
1143 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1144 "Headphone Playback Volume",
1145 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1146 if (err < 0)
1147 return err;
1148 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1149 "Headphone Playback Switch",
1150 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1151 if (err < 0)
1152 return err;
1153
1154 return 0;
1155}
1156
1157/* create playback/capture controls for input pins */
1158static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1159 const struct auto_pin_cfg *cfg)
1160{
1161 static char *labels[] = {
1162 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1163 };
1164 struct hda_input_mux *imux = &spec->private_imux;
1165 int i, err, idx = 0;
1166
1167 /* for internal loopback recording select */
1168 imux->items[imux->num_items].label = "Stereo Mixer";
1169 imux->items[imux->num_items].index = idx;
1170 imux->num_items++;
1171
1172 for (i = 0; i < AUTO_PIN_LAST; i++) {
1173 if (!cfg->input_pins[i])
1174 continue;
1175
1176 switch (cfg->input_pins[i]) {
1177 case 0x1d: /* Mic */
1178 idx = 2;
1179 break;
1180
1181 case 0x1e: /* Line In */
1182 idx = 3;
1183 break;
1184
1185 case 0x21: /* Front Mic */
1186 idx = 4;
1187 break;
1188
1189 case 0x23: /* CD */
1190 idx = 1;
1191 break;
1192 }
1193 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1194 idx, 0x18);
1195 if (err < 0)
1196 return err;
1197 imux->items[imux->num_items].label = labels[i];
1198 imux->items[imux->num_items].index = idx;
1199 imux->num_items++;
1200 }
1201 return 0;
1202}
1203
1204static int vt1709_parse_auto_config(struct hda_codec *codec)
1205{
1206 struct via_spec *spec = codec->spec;
1207 int err;
1208
1209 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1210 if (err < 0)
1211 return err;
1212 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1213 if (err < 0)
1214 return err;
1215 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1216 return 0; /* can't find valid BIOS pin config */
1217
1218 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1219 if (err < 0)
1220 return err;
1221 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1222 if (err < 0)
1223 return err;
1224 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1225 if (err < 0)
1226 return err;
1227
1228 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1229
1230 if (spec->autocfg.dig_out_pin)
1231 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
1232 if (spec->autocfg.dig_in_pin)
1233 spec->dig_in_nid = VT1709_DIGIN_NID;
1234
1235 if (spec->kctl_alloc)
1236 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1237
1238 spec->input_mux = &spec->private_imux;
1239
1240 return 1;
1241}
1242
1243static int patch_vt1709_10ch(struct hda_codec *codec)
1244{
1245 struct via_spec *spec;
1246 int err;
1247
1248 /* create a codec specific record */
1249 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1250 if (spec == NULL)
1251 return -ENOMEM;
1252
1253 codec->spec = spec;
1254
1255 err = vt1709_parse_auto_config(codec);
1256 if (err < 0) {
1257 via_free(codec);
1258 return err;
1259 } else if (!err) {
1260 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1261 "Using genenic mode...\n");
1262 }
1263
1264 spec->init_verbs = vt1709_10ch_volume_init_verbs;
1265
1266 spec->stream_name_analog = "VT1709 Analog";
1267 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1268 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1269
1270 spec->stream_name_digital = "VT1709 Digital";
1271 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1272 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1273
1274
1275 if (!spec->adc_nids && spec->input_mux) {
1276 spec->adc_nids = vt1709_adc_nids;
1277 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1278 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1279 spec->num_mixers++;
1280 }
1281
1282 codec->patch_ops = via_patch_ops;
1283
1284 codec->patch_ops.init = via_auto_init;
1285
1286 return 0;
1287}
1288/*
1289 * generic initialization of ADC, input mixers and output mixers
1290 */
1291static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1292 /*
1293 * Unmute ADC0-2 and set the default input to mic-in
1294 */
1295 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1296 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1297 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1298
1299
1300 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1301 * mixer widget
1302 */
1303 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1304 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1305 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1306 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1307 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1308 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1309
1310 /*
1311 * Set up output selector (0x1a, 0x1b, 0x29)
1312 */
1313 /* set vol=0 to output mixers */
1314 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1315 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1316 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1317
1318 /*
1319 * Unmute PW3 and PW4
1320 */
1321 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1322 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1323
1324 /* Set input of PW4 as MW0 */
1325 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
1326 /* Set mic as default input of sw0 */
1327 {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
1328 /* PW9 Output enable */
1329 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1330 { }
1331};
1332
1333static int patch_vt1709_6ch(struct hda_codec *codec)
1334{
1335 struct via_spec *spec;
1336 int err;
1337
1338 /* create a codec specific record */
1339 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1340 if (spec == NULL)
1341 return -ENOMEM;
1342
1343 codec->spec = spec;
1344
1345 err = vt1709_parse_auto_config(codec);
1346 if (err < 0) {
1347 via_free(codec);
1348 return err;
1349 } else if (!err) {
1350 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1351 "Using genenic mode...\n");
1352 }
1353
1354 spec->init_verbs = vt1709_6ch_volume_init_verbs;
1355
1356 spec->stream_name_analog = "VT1709 Analog";
1357 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1358 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1359
1360 spec->stream_name_digital = "VT1709 Digital";
1361 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1362 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1363
1364
1365 if (!spec->adc_nids && spec->input_mux) {
1366 spec->adc_nids = vt1709_adc_nids;
1367 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1368 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1369 spec->num_mixers++;
1370 }
1371
1372 codec->patch_ops = via_patch_ops;
1373
1374 codec->patch_ops.init = via_auto_init;
1375
1376 return 0;
1377}
1378
1379/*
1380 * patch entries
1381 */
1382struct hda_codec_preset snd_hda_preset_via[] = {
1383 { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
1384 { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
1385 { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
1386 { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
1387 { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1388 { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1389 { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1390 { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1391 { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1392 { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1393 { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1394 { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1395 {} /* terminator */
1396};