aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_via.c
diff options
context:
space:
mode:
authorHarald Welte <HaraldWelte@viatech.com>2008-09-09 03:57:32 -0400
committerJaroslav Kysela <perex@perex.cz>2008-09-09 12:52:02 -0400
commit69e52a80916b39dcdc3667894040c187179fbf2e (patch)
treed530fb033e4728c2565f7e7ef6e0908a821b69ee /sound/pci/hda/patch_via.c
parentd949cac1ea8596f61942437ad741a3fbb412846f (diff)
ALSA: HDA patch_via.c: Mute on headphone plug-in
Signed-off-by: Harald Welte <HaraldWelte@viatech.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r--sound/pci/hda/patch_via.c133
1 files changed, 122 insertions, 11 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 91b72add1a8d..4cad16c532c4 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -32,6 +32,7 @@
32/* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ 32/* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */
33/* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ 33/* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */
34/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ 34/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */
35/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */
35/* */ 36/* */
36/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 37/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
37 38
@@ -83,6 +84,9 @@
83#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397) 84#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397)
84#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398) 85#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398)
85 86
87#define VIA_HP_EVENT 0x01
88#define VIA_GPIO_EVENT 0x02
89
86enum { 90enum {
87 VIA_CTL_WIDGET_VOL, 91 VIA_CTL_WIDGET_VOL,
88 VIA_CTL_WIDGET_MUTE, 92 VIA_CTL_WIDGET_MUTE,
@@ -106,7 +110,8 @@ struct via_spec {
106 struct snd_kcontrol_new *mixers[3]; 110 struct snd_kcontrol_new *mixers[3];
107 unsigned int num_mixers; 111 unsigned int num_mixers;
108 112
109 struct hda_verb *init_verbs; 113 struct hda_verb *init_verbs[5];
114 unsigned int num_iverbs;
110 115
111 char *stream_name_analog; 116 char *stream_name_analog;
112 struct hda_pcm_stream *stream_analog_playback; 117 struct hda_pcm_stream *stream_analog_playback;
@@ -605,10 +610,85 @@ static void via_free(struct hda_codec *codec)
605 kfree(codec->spec); 610 kfree(codec->spec);
606} 611}
607 612
613/* mute internal speaker if HP is plugged */
614static void via_hp_automute(struct hda_codec *codec)
615{
616 unsigned int present;
617 struct via_spec *spec = codec->spec;
618
619 present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
620 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
621 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
622 HDA_OUTPUT, 0, HDA_AMP_MUTE,
623 present ? HDA_AMP_MUTE : 0);
624}
625
626static void via_gpio_control(struct hda_codec *codec)
627{
628 unsigned int gpio_data;
629 unsigned int vol_counter;
630 unsigned int vol;
631 unsigned int master_vol;
632
633 struct via_spec *spec = codec->spec;
634
635 gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
636 AC_VERB_GET_GPIO_DATA, 0) & 0x03;
637
638 vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
639 0xF84, 0) & 0x3F0000) >> 16;
640
641 vol = vol_counter & 0x1F;
642 master_vol = snd_hda_codec_read(codec, 0x1A, 0,
643 AC_VERB_GET_AMP_GAIN_MUTE,
644 AC_AMP_GET_INPUT);
645
646 if (gpio_data == 0x02) {
647 /* unmute line out */
648 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
649 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
650
651 if (vol_counter & 0x20) {
652 /* decrease volume */
653 if (vol > master_vol)
654 vol = master_vol;
655 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
656 0, HDA_AMP_VOLMASK,
657 master_vol-vol);
658 } else {
659 /* increase volume */
660 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
661 HDA_AMP_VOLMASK,
662 ((master_vol+vol) > 0x2A) ? 0x2A :
663 (master_vol+vol));
664 }
665 } else if (!(gpio_data & 0x02)) {
666 /* mute line out */
667 snd_hda_codec_amp_stereo(codec,
668 spec->autocfg.line_out_pins[0],
669 HDA_OUTPUT, 0, HDA_AMP_MUTE,
670 HDA_AMP_MUTE);
671 }
672}
673
674/* unsolicited event for jack sensing */
675static void via_unsol_event(struct hda_codec *codec,
676 unsigned int res)
677{
678 res >>= 26;
679 if (res == VIA_HP_EVENT)
680 via_hp_automute(codec);
681 else if (res == VIA_GPIO_EVENT)
682 via_gpio_control(codec);
683}
684
608static int via_init(struct hda_codec *codec) 685static int via_init(struct hda_codec *codec)
609{ 686{
610 struct via_spec *spec = codec->spec; 687 struct via_spec *spec = codec->spec;
611 snd_hda_sequence_write(codec, spec->init_verbs); 688 int i;
689 for (i = 0; i < spec->num_iverbs; i++)
690 snd_hda_sequence_write(codec, spec->init_verbs[i]);
691
612 /* Lydia Add for EAPD enable */ 692 /* Lydia Add for EAPD enable */
613 if (!spec->dig_in_nid) { /* No Digital In connection */ 693 if (!spec->dig_in_nid) { /* No Digital In connection */
614 if (IS_VT1708_VENDORID(codec->vendor_id)) { 694 if (IS_VT1708_VENDORID(codec->vendor_id)) {
@@ -924,7 +1004,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
924 if (spec->kctl_alloc) 1004 if (spec->kctl_alloc)
925 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 1005 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
926 1006
927 spec->init_verbs = vt1708_volume_init_verbs; 1007 spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
928 1008
929 spec->input_mux = &spec->private_imux; 1009 spec->input_mux = &spec->private_imux;
930 1010
@@ -1016,6 +1096,11 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = {
1016 { } /* end */ 1096 { } /* end */
1017}; 1097};
1018 1098
1099static struct hda_verb vt1709_uniwill_init_verbs[] = {
1100 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
1101 { }
1102};
1103
1019/* 1104/*
1020 * generic initialization of ADC, input mixers and output mixers 1105 * generic initialization of ADC, input mixers and output mixers
1021 */ 1106 */
@@ -1425,7 +1510,8 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
1425 "Using genenic mode...\n"); 1510 "Using genenic mode...\n");
1426 } 1511 }
1427 1512
1428 spec->init_verbs = vt1709_10ch_volume_init_verbs; 1513 spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
1514 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
1429 1515
1430 spec->stream_name_analog = "VT1709 Analog"; 1516 spec->stream_name_analog = "VT1709 Analog";
1431 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; 1517 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
@@ -1446,6 +1532,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
1446 codec->patch_ops = via_patch_ops; 1532 codec->patch_ops = via_patch_ops;
1447 1533
1448 codec->patch_ops.init = via_auto_init; 1534 codec->patch_ops.init = via_auto_init;
1535 codec->patch_ops.unsol_event = via_unsol_event;
1449#ifdef CONFIG_SND_HDA_POWER_SAVE 1536#ifdef CONFIG_SND_HDA_POWER_SAVE
1450 spec->loopback.amplist = vt1709_loopbacks; 1537 spec->loopback.amplist = vt1709_loopbacks;
1451#endif 1538#endif
@@ -1516,7 +1603,8 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
1516 "Using genenic mode...\n"); 1603 "Using genenic mode...\n");
1517 } 1604 }
1518 1605
1519 spec->init_verbs = vt1709_6ch_volume_init_verbs; 1606 spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
1607 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
1520 1608
1521 spec->stream_name_analog = "VT1709 Analog"; 1609 spec->stream_name_analog = "VT1709 Analog";
1522 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; 1610 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
@@ -1537,6 +1625,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
1537 codec->patch_ops = via_patch_ops; 1625 codec->patch_ops = via_patch_ops;
1538 1626
1539 codec->patch_ops.init = via_auto_init; 1627 codec->patch_ops.init = via_auto_init;
1628 codec->patch_ops.unsol_event = via_unsol_event;
1540#ifdef CONFIG_SND_HDA_POWER_SAVE 1629#ifdef CONFIG_SND_HDA_POWER_SAVE
1541 spec->loopback.amplist = vt1709_loopbacks; 1630 spec->loopback.amplist = vt1709_loopbacks;
1542#endif 1631#endif
@@ -1636,6 +1725,11 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
1636 { } 1725 { }
1637}; 1726};
1638 1727
1728static struct hda_verb vt1708B_uniwill_init_verbs[] = {
1729 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
1730 { }
1731};
1732
1639static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { 1733static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
1640 .substreams = 1, 1734 .substreams = 1,
1641 .channels_min = 2, 1735 .channels_min = 2,
@@ -1956,7 +2050,8 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
1956 "from BIOS. Using genenic mode...\n"); 2050 "from BIOS. Using genenic mode...\n");
1957 } 2051 }
1958 2052
1959 spec->init_verbs = vt1708B_8ch_volume_init_verbs; 2053 spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
2054 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
1960 2055
1961 spec->stream_name_analog = "VT1708B Analog"; 2056 spec->stream_name_analog = "VT1708B Analog";
1962 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback; 2057 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
@@ -1976,6 +2071,7 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
1976 codec->patch_ops = via_patch_ops; 2071 codec->patch_ops = via_patch_ops;
1977 2072
1978 codec->patch_ops.init = via_auto_init; 2073 codec->patch_ops.init = via_auto_init;
2074 codec->patch_ops.unsol_event = via_unsol_event;
1979#ifdef CONFIG_SND_HDA_POWER_SAVE 2075#ifdef CONFIG_SND_HDA_POWER_SAVE
1980 spec->loopback.amplist = vt1708B_loopbacks; 2076 spec->loopback.amplist = vt1708B_loopbacks;
1981#endif 2077#endif
@@ -2005,7 +2101,8 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
2005 "from BIOS. Using genenic mode...\n"); 2101 "from BIOS. Using genenic mode...\n");
2006 } 2102 }
2007 2103
2008 spec->init_verbs = vt1708B_4ch_volume_init_verbs; 2104 spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
2105 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
2009 2106
2010 spec->stream_name_analog = "VT1708B Analog"; 2107 spec->stream_name_analog = "VT1708B Analog";
2011 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback; 2108 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
@@ -2025,6 +2122,7 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
2025 codec->patch_ops = via_patch_ops; 2122 codec->patch_ops = via_patch_ops;
2026 2123
2027 codec->patch_ops.init = via_auto_init; 2124 codec->patch_ops.init = via_auto_init;
2125 codec->patch_ops.unsol_event = via_unsol_event;
2028#ifdef CONFIG_SND_HDA_POWER_SAVE 2126#ifdef CONFIG_SND_HDA_POWER_SAVE
2029 spec->loopback.amplist = vt1708B_loopbacks; 2127 spec->loopback.amplist = vt1708B_loopbacks;
2030#endif 2128#endif
@@ -2078,6 +2176,11 @@ static struct hda_verb vt1708S_volume_init_verbs[] = {
2078 { } 2176 { }
2079}; 2177};
2080 2178
2179static struct hda_verb vt1708S_uniwill_init_verbs[] = {
2180 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2181 { }
2182};
2183
2081static struct hda_pcm_stream vt1708S_pcm_analog_playback = { 2184static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
2082 .substreams = 2, 2185 .substreams = 2,
2083 .channels_min = 2, 2186 .channels_min = 2,
@@ -2387,7 +2490,8 @@ static int patch_vt1708S(struct hda_codec *codec)
2387 "from BIOS. Using genenic mode...\n"); 2490 "from BIOS. Using genenic mode...\n");
2388 } 2491 }
2389 2492
2390 spec->init_verbs = vt1708S_volume_init_verbs; 2493 spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
2494 spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
2391 2495
2392 spec->stream_name_analog = "VT1708S Analog"; 2496 spec->stream_name_analog = "VT1708S Analog";
2393 spec->stream_analog_playback = &vt1708S_pcm_analog_playback; 2497 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
@@ -2406,7 +2510,7 @@ static int patch_vt1708S(struct hda_codec *codec)
2406 codec->patch_ops = via_patch_ops; 2510 codec->patch_ops = via_patch_ops;
2407 2511
2408 codec->patch_ops.init = via_auto_init; 2512 codec->patch_ops.init = via_auto_init;
2409 2513 codec->patch_ops.unsol_event = via_unsol_event;
2410#ifdef CONFIG_SND_HDA_POWER_SAVE 2514#ifdef CONFIG_SND_HDA_POWER_SAVE
2411 spec->loopback.amplist = vt1708S_loopbacks; 2515 spec->loopback.amplist = vt1708S_loopbacks;
2412#endif 2516#endif
@@ -2468,6 +2572,12 @@ static struct hda_verb vt1702_volume_init_verbs[] = {
2468 { } 2572 { }
2469}; 2573};
2470 2574
2575static struct hda_verb vt1702_uniwill_init_verbs[] = {
2576 {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT},
2577 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2578 { }
2579};
2580
2471static struct hda_pcm_stream vt1702_pcm_analog_playback = { 2581static struct hda_pcm_stream vt1702_pcm_analog_playback = {
2472 .substreams = 1, 2582 .substreams = 1,
2473 .channels_min = 2, 2583 .channels_min = 2,
@@ -2694,7 +2804,8 @@ static int patch_vt1702(struct hda_codec *codec)
2694 "from BIOS. Using genenic mode...\n"); 2804 "from BIOS. Using genenic mode...\n");
2695 } 2805 }
2696 2806
2697 spec->init_verbs = vt1702_volume_init_verbs; 2807 spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
2808 spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
2698 2809
2699 spec->stream_name_analog = "VT1702 Analog"; 2810 spec->stream_name_analog = "VT1702 Analog";
2700 spec->stream_analog_playback = &vt1702_pcm_analog_playback; 2811 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
@@ -2713,7 +2824,7 @@ static int patch_vt1702(struct hda_codec *codec)
2713 codec->patch_ops = via_patch_ops; 2824 codec->patch_ops = via_patch_ops;
2714 2825
2715 codec->patch_ops.init = via_auto_init; 2826 codec->patch_ops.init = via_auto_init;
2716 2827 codec->patch_ops.unsol_event = via_unsol_event;
2717#ifdef CONFIG_SND_HDA_POWER_SAVE 2828#ifdef CONFIG_SND_HDA_POWER_SAVE
2718 spec->loopback.amplist = vt1702_loopbacks; 2829 spec->loopback.amplist = vt1702_loopbacks;
2719#endif 2830#endif