diff options
author | Harald Welte <HaraldWelte@viatech.com> | 2008-09-09 03:57:32 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-09-09 12:52:02 -0400 |
commit | 69e52a80916b39dcdc3667894040c187179fbf2e (patch) | |
tree | d530fb033e4728c2565f7e7ef6e0908a821b69ee /sound | |
parent | d949cac1ea8596f61942437ad741a3fbb412846f (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')
-rw-r--r-- | sound/pci/hda/patch_via.c | 133 |
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 | |||
86 | enum { | 90 | enum { |
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 */ | ||
614 | static 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 | |||
626 | static 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 */ | ||
675 | static 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 | |||
608 | static int via_init(struct hda_codec *codec) | 685 | static 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 | ||
1099 | static 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 | ||
1728 | static struct hda_verb vt1708B_uniwill_init_verbs[] = { | ||
1729 | {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | ||
1730 | { } | ||
1731 | }; | ||
1732 | |||
1639 | static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { | 1733 | static 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 | ||
2179 | static struct hda_verb vt1708S_uniwill_init_verbs[] = { | ||
2180 | {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | ||
2181 | { } | ||
2182 | }; | ||
2183 | |||
2081 | static struct hda_pcm_stream vt1708S_pcm_analog_playback = { | 2184 | static 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 | ||
2575 | static 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 | |||
2471 | static struct hda_pcm_stream vt1702_pcm_analog_playback = { | 2581 | static 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 |