diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/Makefile | 11 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 68 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 33 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 12 | ||||
-rw-r--r-- | sound/pci/hda/hda_patch.h | 6 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 165 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 24 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 1311 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 2367 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 692 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 1396 |
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 @@ | |||
1 | snd-hda-intel-objs := hda_intel.o | 1 | snd-hda-intel-objs := hda_intel.o |
2 | snd-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 | 2 | snd-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 | ||
3 | ifdef CONFIG_PROC_FS | 12 | ifdef CONFIG_PROC_FS |
4 | snd-hda-codec-objs += hda_proc.o | 13 | snd-hda-codec-objs += hda_proc.o |
5 | endif | 14 | endif |
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 { | |||
52 | static struct hda_vendor_id hda_vendor_ids[] = { | 52 | static 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 | */ |
1725 | int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl) | 1722 | int 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 | */ | ||
1508 | static const struct snd_pci_quirk position_fix_list[] __devinitdata = { | ||
1509 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), | ||
1510 | {} | ||
1511 | }; | ||
1512 | |||
1513 | static 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 | */ |
1507 | static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | 1533 | static 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 | */ |
176 | struct hda_board_config { | 176 | int 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 | |||
183 | int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl); | ||
184 | int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); | 179 | int 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[]; | |||
14 | extern struct hda_codec_preset snd_hda_preset_si3054[]; | 14 | extern struct hda_codec_preset snd_hda_preset_si3054[]; |
15 | /* ATI HDMI codecs */ | 15 | /* ATI HDMI codecs */ |
16 | extern struct hda_codec_preset snd_hda_preset_atihdmi[]; | 16 | extern struct hda_codec_preset snd_hda_preset_atihdmi[]; |
17 | /* Conexant audio codec */ | ||
18 | extern struct hda_codec_preset snd_hda_preset_conexant[]; | ||
19 | /* VIA codecs */ | ||
20 | extern struct hda_codec_preset snd_hda_preset_via[]; | ||
17 | 21 | ||
18 | static const struct hda_codec_preset *hda_preset_tables[] = { | 22 | static 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 */ |
784 | static struct hda_verb ad1986a_eapd_init_verbs[] = { | 784 | static 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 */ | ||
790 | static 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 */ |
790 | enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD }; | 801 | enum { |
791 | 802 | AD1986A_6STACK, | |
792 | static 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, | 810 | static 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 */ | 818 | static 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 */ |
1394 | enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD }; | 1414 | enum { |
1415 | AD1981_BASIC, | ||
1416 | AD1981_HP, | ||
1417 | AD1981_THINKPAD, | ||
1418 | AD1981_MODELS | ||
1419 | }; | ||
1420 | |||
1421 | static const char *ad1981_models[AD1981_MODELS] = { | ||
1422 | [AD1981_HP] = "hp", | ||
1423 | [AD1981_THINKPAD] = "thinkpad", | ||
1424 | [AD1981_BASIC] = "basic", | ||
1425 | }; | ||
1395 | 1426 | ||
1396 | static struct hda_board_config ad1981_cfg_tbl[] = { | 1427 | static 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 | ||
2568 | static struct hda_board_config ad1988_cfg_tbl[] = { | 2597 | static 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 | ||
2579 | static int patch_ad1988(struct hda_codec *codec) | 2607 | static 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 | ||
45 | struct cmi_spec { | 46 | struct cmi_spec { |
@@ -603,14 +604,17 @@ static void cmi9880_free(struct hda_codec *codec) | |||
603 | /* | 604 | /* |
604 | */ | 605 | */ |
605 | 606 | ||
606 | static struct hda_board_config cmi9880_cfg_tbl[] = { | 607 | static 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 | |||
616 | static 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 | |||
43 | struct 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 | |||
91 | static 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 | |||
99 | static 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 | |||
111 | static 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 | */ | ||
122 | static 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 | |||
130 | static 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 | */ | ||
141 | static 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 | |||
153 | static 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 | |||
165 | static 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 | |||
177 | static 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 | |||
189 | static 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 | |||
200 | static 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 | |||
207 | static 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 | |||
244 | static 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 | |||
253 | static 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 | |||
264 | static 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 | |||
276 | static 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 | |||
286 | static 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 | ||
301 | static 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 | |||
317 | static 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 | |||
342 | static 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 | |||
357 | static 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 | |||
367 | static 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 | |||
380 | static 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 | |||
403 | static 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 | |||
412 | static 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 | |||
422 | static 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 | |||
442 | static 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 | |||
452 | static 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 | |||
466 | static 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 | |||
496 | static 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 | |||
506 | static 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 | |||
520 | static 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 | |||
555 | static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; | ||
556 | static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; | ||
557 | static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; | ||
558 | #define CXT5045_SPDIF_OUT 0x13 | ||
559 | |||
560 | static struct hda_channel_mode cxt5045_modes[1] = { | ||
561 | { 2, NULL }, | ||
562 | }; | ||
563 | |||
564 | static 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 */ | ||
573 | static 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 */ | ||
591 | static 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 */ | ||
611 | static 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 */ | ||
624 | static 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 | |||
635 | static 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 | |||
667 | static 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 | */ | ||
695 | static 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 | |||
706 | static 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 | |||
750 | static 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 */ | ||
801 | static int cxt5045_init(struct hda_codec *codec) | ||
802 | { | ||
803 | conexant_init(codec); | ||
804 | cxt5045_hp_automute(codec); | ||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | |||
809 | enum { | ||
810 | CXT5045_LAPTOP, /* Laptops w/ EAPD support */ | ||
811 | #ifdef CONFIG_SND_DEBUG | ||
812 | CXT5045_TEST, | ||
813 | #endif | ||
814 | CXT5045_MODELS | ||
815 | }; | ||
816 | |||
817 | static const char *cxt5045_models[CXT5045_MODELS] = { | ||
818 | [CXT5045_LAPTOP] = "laptop", | ||
819 | #ifdef CONFIG_SND_DEBUG | ||
820 | [CXT5045_TEST] = "test", | ||
821 | #endif | ||
822 | }; | ||
823 | |||
824 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | ||
825 | SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP), | ||
826 | {} | ||
827 | }; | ||
828 | |||
829 | static 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 | |||
884 | static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; | ||
885 | static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; | ||
886 | static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; | ||
887 | #define CXT5047_SPDIF_OUT 0x11 | ||
888 | |||
889 | static struct hda_channel_mode cxt5047_modes[1] = { | ||
890 | { 2, NULL }, | ||
891 | }; | ||
892 | |||
893 | static struct hda_input_mux cxt5047_capture_source = { | ||
894 | .num_items = 2, | ||
895 | .items = { | ||
896 | { "ExtMic", 0x1 }, | ||
897 | { "IntMic", 0x2 }, | ||
898 | } | ||
899 | }; | ||
900 | |||
901 | static 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 */ | ||
909 | static 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 */ | ||
928 | static 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 */ | ||
948 | static 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 */ | ||
961 | static 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 */ | ||
984 | static 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 | |||
998 | static 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 | |||
1025 | static 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 | |||
1051 | static 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 */ | ||
1073 | static 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 */ | ||
1082 | static 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 | ||
1093 | static 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 | |||
1104 | static 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 | |||
1152 | static 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 */ | ||
1214 | static 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 | |||
1223 | enum { | ||
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 | |||
1233 | static 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 | |||
1242 | static 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 | |||
1250 | static 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 | |||
1307 | struct 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 */ |
37 | enum { | 41 | enum { |
@@ -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 */ |
78 | enum { | 85 | enum { |
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 */ | ||
113 | enum { | ||
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 */ |
99 | enum { | 123 | enum { |
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 */ | ||
1048 | static 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 | |||
1077 | static 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 | |||
1091 | static 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 | */ | ||
1339 | static 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 | */ | ||
1377 | static 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 | |||
1406 | static 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 */ | ||
1412 | static 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 | |||
1433 | static 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 | |||
1444 | static 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 | |||
1457 | static 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 | } | ||
1475 | static 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 | ||
2128 | static struct hda_board_config alc880_cfg_tbl[] = { | 2364 | static 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 | |||
2391 | static 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 | */ |
3094 | static struct snd_kcontrol_new alc260_acer_mixer[] = { | 3331 | static 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 | */ |
3931 | static struct hda_board_config alc260_cfg_tbl[] = { | 4174 | static 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 | |||
4186 | static 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 */ | ||
4564 | static 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 | |||
4575 | static 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 | }; | ||
4625 | static 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 | */ |
4438 | static struct hda_board_config alc882_cfg_tbl[] = { | 4779 | static 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*/ | 4787 | static 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 | ||
5130 | static 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 | ||
5251 | static 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 | |||
5288 | static 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 | |||
5321 | static 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 | |||
4878 | static struct snd_kcontrol_new alc883_chmode_mixer[] = { | 5346 | static 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 | ||
5434 | static 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 */ | ||
5454 | static 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 | |||
5467 | static 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 | */ |
5060 | static struct hda_board_config alc883_cfg_tbl[] = { | 5567 | static 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) */ | 5581 | static 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 | ||
5931 | static 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 | |||
5358 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | 5949 | static 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 | ||
5971 | static 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 | |||
5989 | static 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 | ||
6077 | static 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 | |||
6083 | static 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 */ | ||
6094 | static 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 */ | ||
6126 | static 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 | |||
6134 | static 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 */ | ||
6166 | static 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 | ||
6524 | static 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 | */ |
5869 | static struct hda_board_config alc262_cfg_tbl[] = { | 6675 | static 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 */ | 6686 | static 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 */ | ||
6944 | static 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 */ | ||
6958 | static 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 | |||
6976 | static 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 | ||
6083 | static struct snd_kcontrol_new alc861_base_mixer[] = { | 6983 | static 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 | |||
7059 | static 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 | |||
6158 | static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { | 7080 | static 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 | ||
7122 | static 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 */ | ||
7165 | static 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 | ||
7361 | static 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 */ | ||
7423 | static 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 | ||
7481 | static 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 */ | ||
7488 | static 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 | |||
7504 | static 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 | */ |
6713 | static struct hda_board_config alc861_cfg_tbl[] = { | 7787 | static 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 }, | 7799 | static 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 | ||
6796 | static int patch_alc861(struct hda_codec *codec) | 7920 | static 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 | |||
7983 | static 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 | */ | ||
7995 | static hda_nid_t alc660vd_dac_nids[3] = { | ||
7996 | /* front, rear, clfe, rear_surr */ | ||
7997 | 0x02, 0x04, 0x03 | ||
7998 | }; | ||
7999 | |||
8000 | static 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 */ | ||
8007 | static 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 | |||
8020 | static 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 | */ | ||
8049 | static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { | ||
8050 | { 2, NULL } | ||
8051 | }; | ||
8052 | |||
8053 | /* | ||
8054 | * 6ch mode | ||
8055 | */ | ||
8056 | static 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 | */ | ||
8067 | static 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 | |||
8075 | static struct hda_channel_mode alc861vd_6stack_modes[2] = { | ||
8076 | { 6, alc861vd_6stack_ch6_init }, | ||
8077 | { 8, alc861vd_6stack_ch8_init }, | ||
8078 | }; | ||
8079 | |||
8080 | static 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 | |||
8091 | static 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 | */ | ||
8114 | static 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 | |||
8153 | static 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 | */ | ||
8182 | static 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 | */ | ||
8232 | static 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 | */ | ||
8263 | static 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 | */ | ||
8313 | static 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 | |||
8321 | static 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 | |||
8330 | static 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 | */ | ||
8380 | static 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 | |||
8390 | static 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 | |||
8404 | static 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 | |||
8417 | static 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 */ | ||
8443 | static 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 */ | ||
8502 | static 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 */ | ||
8552 | static 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 */ | ||
8593 | static 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 | |||
8600 | static 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 | */ |
6851 | struct hda_codec_preset snd_hda_preset_realtek[] = { | 8663 | struct 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 | 40 | enum { |
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 | 45 | enum { |
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 | |||
50 | enum { | ||
51 | STAC_925x_REF, | ||
52 | STAC_M2_2, | ||
53 | STAC_MA6, | ||
54 | STAC_925x_MODELS | ||
55 | }; | ||
56 | |||
57 | enum { | ||
58 | STAC_D945_REF, | ||
59 | STAC_D945GTP3, | ||
60 | STAC_D945GTP5, | ||
61 | STAC_MACMINI, | ||
62 | STAC_922X_MODELS | ||
63 | }; | ||
64 | |||
65 | enum { | ||
66 | STAC_D965_REF, | ||
67 | STAC_D965_3ST, | ||
68 | STAC_D965_5ST, | ||
69 | STAC_927X_MODELS | ||
70 | }; | ||
48 | 71 | ||
49 | struct sigmatel_spec { | 72 | struct 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 | ||
139 | static hda_nid_t stac925x_adc_nids[1] = { | ||
140 | 0x03, | ||
141 | }; | ||
142 | |||
143 | static hda_nid_t stac925x_mux_nids[1] = { | ||
144 | 0x0f, | ||
145 | }; | ||
146 | |||
147 | static hda_nid_t stac925x_dac_nids[1] = { | ||
148 | 0x02, | ||
149 | }; | ||
150 | |||
110 | static hda_nid_t stac922x_adc_nids[2] = { | 151 | static 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 | ||
175 | static hda_nid_t stac9205_dmic_nids[3] = { | ||
176 | 0x17, 0x18, 0 | ||
177 | }; | ||
178 | |||
134 | static hda_nid_t stac9200_pin_nids[8] = { | 179 | static 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 | ||
184 | static hda_nid_t stac925x_pin_nids[8] = { | ||
185 | 0x07, 0x08, 0x0a, 0x0b, | ||
186 | 0x0c, 0x0d, 0x10, 0x11, | ||
187 | }; | ||
188 | |||
139 | static hda_nid_t stac922x_pin_nids[10] = { | 189 | static 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 | ||
207 | static 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 | |||
215 | static 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 | |||
225 | static 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 | |||
157 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 235 | static 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 | ||
268 | static struct hda_verb stac925x_core_init[] = { | ||
269 | /* set dac0mux for dac converter */ | ||
270 | { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
271 | {} | ||
272 | }; | ||
273 | |||
190 | static struct hda_verb stac922x_core_init[] = { | 274 | static 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 | ||
319 | static 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 */ |
236 | static struct snd_kcontrol_new stac922x_mixer[] = { | 337 | static 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 | ||
266 | static snd_kcontrol_new_t stac927x_mixer[] = { | 367 | static 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 | ||
281 | static snd_kcontrol_new_t stac9205_mixer[] = { | 382 | static 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 | ||
330 | static unsigned int *stac9200_brd_tbl[] = { | 439 | static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { |
331 | ref9200_pin_configs, | 440 | [STAC_REF] = ref9200_pin_configs, |
441 | }; | ||
442 | |||
443 | static const char *stac9200_models[STAC_9200_MODELS] = { | ||
444 | [STAC_REF] = "ref", | ||
332 | }; | 445 | }; |
333 | 446 | ||
334 | static struct hda_board_config stac9200_cfg_tbl[] = { | 447 | static 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 | |||
463 | static unsigned int ref925x_pin_configs[8] = { | ||
464 | 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, | ||
465 | 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e, | ||
466 | }; | ||
467 | |||
468 | static unsigned int stac925x_MA6_pin_configs[8] = { | ||
469 | 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, | ||
470 | 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e, | ||
471 | }; | ||
472 | |||
473 | static unsigned int stac925xM2_2_pin_configs[8] = { | ||
474 | 0x40c003f3, 0x424503f2, 0x041800f4, 0x02a19020, | ||
475 | 0x50a103F0, 0x90100210, 0x400003f1, 0x9033032e, | ||
476 | }; | ||
477 | |||
478 | static 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 | |||
484 | static const char *stac925x_models[STAC_925x_MODELS] = { | ||
485 | [STAC_REF] = "ref", | ||
486 | [STAC_M2_2] = "m2-2", | ||
487 | [STAC_MA6] = "m6", | ||
488 | }; | ||
489 | |||
490 | static 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 | ||
367 | static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { | 518 | static 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 | ||
374 | static struct hda_board_config stac922x_cfg_tbl[] = { | 525 | static 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 */ | 532 | static 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 | ||
486 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { | 617 | static 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 | ||
492 | static struct hda_board_config stac927x_cfg_tbl[] = { | 623 | static 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 */ | 629 | static 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 | ||
586 | static unsigned int ref9205_pin_configs[12] = { | 666 | static 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 | ||
592 | static unsigned int *stac9205_brd_tbl[] = { | 672 | static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { |
593 | ref9205_pin_configs, | 673 | ref9205_pin_configs, |
594 | }; | 674 | }; |
595 | 675 | ||
596 | static struct hda_board_config stac9205_cfg_tbl[] = { | 676 | static 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 */ | 680 | static 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 */ | ||
1241 | static 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 */ | ||
1247 | static 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; | ||
1282 | found: | ||
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 */ |
1158 | static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) | 1293 | static 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 | ||
1788 | static 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 | |||
1636 | static int patch_stac922x(struct hda_codec *codec) | 1838 | static 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 | }; | |
1969 | static struct hda_board_config stac9872_cfg_tbl[] = { | 2196 | |
1970 | { .modelname = "vaio", .config = CXD9872RD_VAIO }, | 2197 | static 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 }, | 2202 | static 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 | |||
65 | enum { | ||
66 | VIA_CTL_WIDGET_VOL, | ||
67 | VIA_CTL_WIDGET_MUTE, | ||
68 | }; | ||
69 | |||
70 | enum { | ||
71 | AUTO_SEQ_FRONT, | ||
72 | AUTO_SEQ_SURROUND, | ||
73 | AUTO_SEQ_CENLFE, | ||
74 | AUTO_SEQ_SIDE | ||
75 | }; | ||
76 | |||
77 | static 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 | |||
83 | struct 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 | |||
121 | static hda_nid_t vt1708_adc_nids[2] = { | ||
122 | /* ADC1-2 */ | ||
123 | 0x15, 0x27 | ||
124 | }; | ||
125 | |||
126 | static hda_nid_t vt1709_adc_nids[3] = { | ||
127 | /* ADC1-2 */ | ||
128 | 0x14, 0x15, 0x16 | ||
129 | }; | ||
130 | |||
131 | /* add dynamic controls */ | ||
132 | static 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 */ | ||
165 | static 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 | |||
184 | static 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 | |||
196 | static 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 | |||
208 | static 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 | |||
218 | static 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 | */ | ||
236 | static 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 | |||
244 | static 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 | |||
255 | static 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 */ | ||
278 | static 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 | */ | ||
301 | static 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 | |||
335 | static 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 | |||
343 | static 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 | |||
354 | static 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 | */ | ||
365 | static 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 | |||
373 | static 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 | */ | ||
384 | static 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 | |||
397 | static 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 | |||
407 | static 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 | |||
419 | static 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 | |||
430 | static 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 | |||
441 | static struct hda_pcm_stream vt1708_pcm_digital_capture = { | ||
442 | .substreams = 1, | ||
443 | .channels_min = 2, | ||
444 | .channels_max = 2, | ||
445 | }; | ||
446 | |||
447 | static 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 | |||
473 | static 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 | |||
511 | static 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 | |||
528 | static 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 | */ | ||
539 | static 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 | */ | ||
558 | static 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 */ | ||
569 | static 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 */ | ||
604 | static 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 | |||
684 | static 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 */ | ||
708 | static 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 | |||
754 | static 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 */ | ||
796 | static 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 | |||
805 | static 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 */ | ||
852 | static 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 | */ | ||
878 | static 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 | |||
920 | static 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 | |||
932 | static 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 | |||
944 | static 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 | |||
955 | static 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 | |||
966 | static struct hda_pcm_stream vt1709_pcm_digital_capture = { | ||
967 | .substreams = 1, | ||
968 | .channels_min = 2, | ||
969 | .channels_max = 2, | ||
970 | }; | ||
971 | |||
972 | static 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 */ | ||
1043 | static 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 | |||
1131 | static 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 */ | ||
1158 | static 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 | |||
1204 | static 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 | |||
1243 | static 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 | */ | ||
1291 | static 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 | |||
1333 | static 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 | */ | ||
1382 | struct 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 | }; | ||