aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKailang Yang <kailang@realtek.com.tw>2007-10-16 08:30:01 -0400
committerJaroslav Kysela <perex@perex.cz>2007-10-16 10:51:25 -0400
commitc9b58006be7e471a5f55d171cbaa08f4aa8078ea (patch)
tree8ec10fb70342dc48ee6ae5125d24e76c09c88c1b
parent291702f017efdfe556cb87b8530eb7d1ff08cbae (diff)
[ALSA] hda-codec - Fix SKU ID function for realtek codecs
Fixed SKU ID function for realtek codecs. It's used by the automatic BIOS configuration mode. Now it supports the correct jack-detection mechanism, too. Signed-off-by: Kailang Yang <kailang@realtek.com.tw> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--sound/pci/hda/patch_realtek.c193
1 files changed, 168 insertions, 25 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index c8ca97b2c31d..53b0428abfc2 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -662,6 +662,44 @@ static struct hda_verb alc_gpio3_init_verbs[] = {
662 { } 662 { }
663}; 663};
664 664
665static void alc_sku_automute(struct hda_codec *codec)
666{
667 struct alc_spec *spec = codec->spec;
668 unsigned int mute;
669 unsigned int present;
670 unsigned int hp_nid = spec->autocfg.hp_pins[0];
671 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
672
673 /* need to execute and sync at first */
674 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
675 present = snd_hda_codec_read(codec, hp_nid, 0,
676 AC_VERB_GET_PIN_SENSE, 0);
677 spec->jack_present = (present & 0x80000000) != 0;
678 if (spec->jack_present) {
679 /* mute internal speaker */
680 snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
681 HDA_AMP_MUTE, HDA_AMP_MUTE);
682 } else {
683 /* unmute internal speaker if necessary */
684 mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0);
685 snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
686 HDA_AMP_MUTE, mute);
687 }
688}
689
690/* unsolicited event for HP jack sensing */
691static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
692{
693 if (codec->vendor_id == 0x10ec0880)
694 res >>= 28;
695 else
696 res >>= 26;
697 if (res != ALC880_HP_EVENT)
698 return;
699
700 alc_sku_automute(codec);
701}
702
665/* 32-bit subsystem ID for BIOS loading in HD Audio codec. 703/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
666 * 31 ~ 16 : Manufacture ID 704 * 31 ~ 16 : Manufacture ID
667 * 15 ~ 8 : SKU ID 705 * 15 ~ 8 : SKU ID
@@ -672,13 +710,48 @@ static void alc_subsystem_id(struct hda_codec *codec,
672 unsigned int porta, unsigned int porte, 710 unsigned int porta, unsigned int porte,
673 unsigned int portd) 711 unsigned int portd)
674{ 712{
675 unsigned int ass, tmp; 713 unsigned int ass, tmp, i;
714 unsigned nid;
715 struct alc_spec *spec = codec->spec;
676 716
677 ass = codec->subsystem_id; 717 ass = codec->subsystem_id & 0xffff;
678 if (!(ass & 1)) 718 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
719 goto do_sku;
720
721 /*
722 * 31~30 : port conetcivity
723 * 29~21 : reserve
724 * 20 : PCBEEP input
725 * 19~16 : Check sum (15:1)
726 * 15~1 : Custom
727 * 0 : override
728 */
729 nid = 0x1d;
730 if (codec->vendor_id == 0x10ec0260)
731 nid = 0x17;
732 ass = snd_hda_codec_read(codec, nid, 0,
733 AC_VERB_GET_CONFIG_DEFAULT, 0);
734 if (!(ass & 1) && !(ass & 0x100000))
735 return;
736 if ((ass >> 30) != 1) /* no physical connection */
679 return; 737 return;
680 738
681 /* Override */ 739 /* check sum */
740 tmp = 0;
741 for (i = 1; i < 16; i++) {
742 if ((ass >> i) && 1)
743 tmp++;
744 }
745 if (((ass >> 16) & 0xf) != tmp)
746 return;
747do_sku:
748 /*
749 * 0 : override
750 * 1 : Swap Jack
751 * 2 : 0 --> Desktop, 1 --> Laptop
752 * 3~5 : External Amplifier control
753 * 7~6 : Reserved
754 */
682 tmp = (ass & 0x38) >> 3; /* external Amp control */ 755 tmp = (ass & 0x38) >> 3; /* external Amp control */
683 switch (tmp) { 756 switch (tmp) {
684 case 1: 757 case 1:
@@ -690,38 +763,108 @@ static void alc_subsystem_id(struct hda_codec *codec,
690 case 7: 763 case 7:
691 snd_hda_sequence_write(codec, alc_gpio3_init_verbs); 764 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
692 break; 765 break;
693 case 5: 766 case 5: /* set EAPD output high */
694 switch (codec->vendor_id) { 767 switch (codec->vendor_id) {
695 case 0x10ec0862: 768 case 0x10ec0260:
696 case 0x10ec0660: 769 snd_hda_codec_write(codec, 0x0f, 0,
697 case 0x10ec0662: 770 AC_VERB_SET_EAPD_BTLENABLE, 2);
771 snd_hda_codec_write(codec, 0x10, 0,
772 AC_VERB_SET_EAPD_BTLENABLE, 2);
773 break;
774 case 0x10ec0262:
698 case 0x10ec0267: 775 case 0x10ec0267:
699 case 0x10ec0268: 776 case 0x10ec0268:
777 case 0x10ec0269:
778 case 0x10ec0862:
779 case 0x10ec0662:
700 snd_hda_codec_write(codec, 0x14, 0, 780 snd_hda_codec_write(codec, 0x14, 0,
701 AC_VERB_SET_EAPD_BTLENABLE, 2); 781 AC_VERB_SET_EAPD_BTLENABLE, 2);
702 snd_hda_codec_write(codec, 0x15, 0, 782 snd_hda_codec_write(codec, 0x15, 0,
703 AC_VERB_SET_EAPD_BTLENABLE, 2); 783 AC_VERB_SET_EAPD_BTLENABLE, 2);
704 return; 784 break;
705 } 785 }
706 case 6: 786 switch (codec->vendor_id) {
707 if (ass & 4) { /* bit 2 : 0 = Desktop, 1 = Laptop */ 787 case 0x10ec0260:
708 hda_nid_t port = 0; 788 snd_hda_codec_write(codec, 0x1a, 0,
709 tmp = (ass & 0x1800) >> 11; 789 AC_VERB_SET_COEF_INDEX, 7);
710 switch (tmp) { 790 tmp = snd_hda_codec_read(codec, 0x1a, 0,
711 case 0: port = porta; break; 791 AC_VERB_GET_PROC_COEF, 0);
712 case 1: port = porte; break; 792 snd_hda_codec_write(codec, 0x1a, 0,
713 case 2: port = portd; break; 793 AC_VERB_SET_COEF_INDEX, 7);
714 } 794 snd_hda_codec_write(codec, 0x1a, 0,
715 if (port) 795 AC_VERB_SET_PROC_COEF,
716 snd_hda_codec_write(codec, port, 0, 796 tmp | 0x2010);
717 AC_VERB_SET_EAPD_BTLENABLE, 797 break;
718 2); 798 case 0x10ec0262:
799 case 0x10ec0880:
800 case 0x10ec0882:
801 case 0x10ec0883:
802 case 0x10ec0885:
803 case 0x10ec0888:
804 snd_hda_codec_write(codec, 0x20, 0,
805 AC_VERB_SET_COEF_INDEX, 7);
806 tmp = snd_hda_codec_read(codec, 0x20, 0,
807 AC_VERB_GET_PROC_COEF, 0);
808 snd_hda_codec_write(codec, 0x20, 0,
809 AC_VERB_SET_COEF_INDEX, 7);
810 snd_hda_codec_write(codec, 0x20, 0,
811 AC_VERB_SET_PROC_COEF,
812 tmp | 0x2010);
813 break;
814 case 0x10ec0267:
815 case 0x10ec0268:
816 snd_hda_codec_write(codec, 0x20, 0,
817 AC_VERB_SET_COEF_INDEX, 7);
818 tmp = snd_hda_codec_read(codec, 0x20, 0,
819 AC_VERB_GET_PROC_COEF, 0);
820 snd_hda_codec_write(codec, 0x20, 0,
821 AC_VERB_SET_COEF_INDEX, 7);
822 snd_hda_codec_write(codec, 0x20, 0,
823 AC_VERB_SET_PROC_COEF,
824 tmp | 0x3000);
825 break;
719 } 826 }
720 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); 827 default:
721 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF,
722 (tmp == 5 ? 0x3040 : 0x3050));
723 break; 828 break;
724 } 829 }
830
831 /* is laptop and enable the function "Mute internal speaker
832 * when the external headphone out jack is plugged"
833 */
834 if (!(ass & 0x4) || !(ass & 0x8000))
835 return;
836 /*
837 * 10~8 : Jack location
838 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
839 * 14~13: Resvered
840 * 15 : 1 --> enable the function "Mute internal speaker
841 * when the external headphone out jack is plugged"
842 */
843 if (!spec->autocfg.speaker_pins[0]) {
844 if (spec->multiout.dac_nids[0])
845 spec->autocfg.speaker_pins[0] =
846 spec->multiout.dac_nids[0];
847 else
848 return;
849 }
850
851 if (!spec->autocfg.hp_pins[0]) {
852 tmp = (ass >> 11) & 0x3; /* HP to chassis */
853 if (tmp == 0)
854 spec->autocfg.hp_pins[0] = porta;
855 else if (tmp == 1)
856 spec->autocfg.hp_pins[0] = porte;
857 else if (tmp == 2)
858 spec->autocfg.hp_pins[0] = portd;
859 else
860 return;
861 }
862
863 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
864 AC_VERB_SET_UNSOLICITED_ENABLE,
865 AC_USRSP_EN | ALC880_HP_EVENT);
866 spec->unsol_event = alc_sku_unsol_event;
867 spec->init_hook = alc_sku_automute;
725} 868}
726 869
727/* 870/*