diff options
author | Kailang Yang <kailang@realtek.com.tw> | 2007-06-05 06:30:55 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2007-07-20 05:11:24 -0400 |
commit | a361d84bfcd938208dea6c84aa19994b3d69e15d (patch) | |
tree | c3b05f27ca6331478b29dd8ecd52c3c44d468e3c /sound | |
parent | 7d87de2db2213e6e9413532445b14c92dae42c85 (diff) |
[ALSA] hda-codec - Add support of ALC268 codec
Added the support of new ALC268 codec chip.
Signed-off-by: Kailang Yang <kailang@realtek.com.tw>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c92c97c6cbe5..49a0fa8ec679 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -98,6 +98,13 @@ enum { | |||
98 | ALC262_MODEL_LAST /* last tag */ | 98 | ALC262_MODEL_LAST /* last tag */ |
99 | }; | 99 | }; |
100 | 100 | ||
101 | /* ALC268 models */ | ||
102 | enum { | ||
103 | ALC268_3ST, | ||
104 | ALC268_AUTO, | ||
105 | ALC268_MODEL_LAST /* last tag */ | ||
106 | }; | ||
107 | |||
101 | /* ALC861 models */ | 108 | /* ALC861 models */ |
102 | enum { | 109 | enum { |
103 | ALC861_3ST, | 110 | ALC861_3ST, |
@@ -7804,6 +7811,515 @@ static int patch_alc262(struct hda_codec *codec) | |||
7804 | } | 7811 | } |
7805 | 7812 | ||
7806 | /* | 7813 | /* |
7814 | * ALC268 channel source setting (2 channel) | ||
7815 | */ | ||
7816 | #define ALC268_DIGOUT_NID ALC880_DIGOUT_NID | ||
7817 | #define alc268_modes alc260_modes | ||
7818 | |||
7819 | static hda_nid_t alc268_dac_nids[2] = { | ||
7820 | /* front, hp */ | ||
7821 | 0x02, 0x03 | ||
7822 | }; | ||
7823 | |||
7824 | static hda_nid_t alc268_adc_nids[2] = { | ||
7825 | /* ADC0-1 */ | ||
7826 | 0x08, 0x07 | ||
7827 | }; | ||
7828 | |||
7829 | static hda_nid_t alc268_adc_nids_alt[1] = { | ||
7830 | /* ADC0 */ | ||
7831 | 0x08 | ||
7832 | }; | ||
7833 | |||
7834 | static struct snd_kcontrol_new alc268_base_mixer[] = { | ||
7835 | /* output mixer control */ | ||
7836 | HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), | ||
7837 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
7838 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), | ||
7839 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
7840 | { } | ||
7841 | }; | ||
7842 | |||
7843 | /* | ||
7844 | * generic initialization of ADC, input mixers and output mixers | ||
7845 | */ | ||
7846 | static struct hda_verb alc268_base_init_verbs[] = { | ||
7847 | /* Unmute DAC0-1 and set vol = 0 */ | ||
7848 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7849 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7850 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7851 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7852 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7853 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7854 | |||
7855 | /* | ||
7856 | * Set up output mixers (0x0c - 0x0e) | ||
7857 | */ | ||
7858 | /* set vol=0 to output mixers */ | ||
7859 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7860 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7861 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7862 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7863 | |||
7864 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7865 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7866 | |||
7867 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
7868 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, | ||
7869 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
7870 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
7871 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
7872 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
7873 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
7874 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
7875 | |||
7876 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7877 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7878 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7879 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7880 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7881 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7882 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7883 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
7884 | |||
7885 | /* FIXME: use matrix-type input source selection */ | ||
7886 | /* Mixer elements: 0x18, 19, 1a, 1c, 14, 15, 0b */ | ||
7887 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
7888 | /* Input mixer2 */ | ||
7889 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
7890 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
7891 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
7892 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
7893 | |||
7894 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
7895 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
7896 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
7897 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
7898 | { } | ||
7899 | }; | ||
7900 | |||
7901 | /* | ||
7902 | * generic initialization of ADC, input mixers and output mixers | ||
7903 | */ | ||
7904 | static struct hda_verb alc268_volume_init_verbs[] = { | ||
7905 | /* set output DAC */ | ||
7906 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7907 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7908 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7909 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7910 | |||
7911 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
7912 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
7913 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
7914 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
7915 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
7916 | |||
7917 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
7918 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7919 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
7920 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7921 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
7922 | |||
7923 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7924 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7925 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7926 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
7927 | |||
7928 | /* set PCBEEP vol = 0 */ | ||
7929 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))}, | ||
7930 | |||
7931 | { } | ||
7932 | }; | ||
7933 | |||
7934 | #define alc268_mux_enum_info alc_mux_enum_info | ||
7935 | #define alc268_mux_enum_get alc_mux_enum_get | ||
7936 | |||
7937 | static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
7938 | struct snd_ctl_elem_value *ucontrol) | ||
7939 | { | ||
7940 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
7941 | struct alc_spec *spec = codec->spec; | ||
7942 | const struct hda_input_mux *imux = spec->input_mux; | ||
7943 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
7944 | static hda_nid_t capture_mixers[3] = { 0x23, 0x24 }; | ||
7945 | hda_nid_t nid = capture_mixers[adc_idx]; | ||
7946 | unsigned int *cur_val = &spec->cur_mux[adc_idx]; | ||
7947 | unsigned int i, idx; | ||
7948 | |||
7949 | idx = ucontrol->value.enumerated.item[0]; | ||
7950 | if (idx >= imux->num_items) | ||
7951 | idx = imux->num_items - 1; | ||
7952 | if (*cur_val == idx && !codec->in_resume) | ||
7953 | return 0; | ||
7954 | for (i = 0; i < imux->num_items; i++) { | ||
7955 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | ||
7956 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
7957 | v | (imux->items[i].index << 8)); | ||
7958 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, | ||
7959 | idx ); | ||
7960 | } | ||
7961 | *cur_val = idx; | ||
7962 | return 1; | ||
7963 | } | ||
7964 | |||
7965 | static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { | ||
7966 | HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), | ||
7967 | HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), | ||
7968 | { | ||
7969 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
7970 | /* The multiple "Capture Source" controls confuse alsamixer | ||
7971 | * So call somewhat different.. | ||
7972 | * FIXME: the controls appear in the "playback" view! | ||
7973 | */ | ||
7974 | /* .name = "Capture Source", */ | ||
7975 | .name = "Input Source", | ||
7976 | .count = 1, | ||
7977 | .info = alc268_mux_enum_info, | ||
7978 | .get = alc268_mux_enum_get, | ||
7979 | .put = alc268_mux_enum_put, | ||
7980 | }, | ||
7981 | { } /* end */ | ||
7982 | }; | ||
7983 | |||
7984 | static struct snd_kcontrol_new alc268_capture_mixer[] = { | ||
7985 | HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), | ||
7986 | HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), | ||
7987 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), | ||
7988 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT), | ||
7989 | { | ||
7990 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
7991 | /* The multiple "Capture Source" controls confuse alsamixer | ||
7992 | * So call somewhat different.. | ||
7993 | * FIXME: the controls appear in the "playback" view! | ||
7994 | */ | ||
7995 | /* .name = "Capture Source", */ | ||
7996 | .name = "Input Source", | ||
7997 | .count = 2, | ||
7998 | .info = alc268_mux_enum_info, | ||
7999 | .get = alc268_mux_enum_get, | ||
8000 | .put = alc268_mux_enum_put, | ||
8001 | }, | ||
8002 | { } /* end */ | ||
8003 | }; | ||
8004 | |||
8005 | static struct hda_input_mux alc268_capture_source = { | ||
8006 | .num_items = 4, | ||
8007 | .items = { | ||
8008 | { "Mic", 0x0 }, | ||
8009 | { "Front Mic", 0x1 }, | ||
8010 | { "Line", 0x2 }, | ||
8011 | { "CD", 0x3 }, | ||
8012 | }, | ||
8013 | }; | ||
8014 | |||
8015 | /* create input playback/capture controls for the given pin */ | ||
8016 | static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | ||
8017 | const char *ctlname, int idx) | ||
8018 | { | ||
8019 | char name[32]; | ||
8020 | int err; | ||
8021 | |||
8022 | sprintf(name, "%s Playback Volume", ctlname); | ||
8023 | if (nid == 0x14) { | ||
8024 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
8025 | HDA_COMPOSE_AMP_VAL(0x02, 3, idx, | ||
8026 | HDA_OUTPUT)); | ||
8027 | if (err < 0) | ||
8028 | return err; | ||
8029 | } else if (nid == 0x15) { | ||
8030 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
8031 | HDA_COMPOSE_AMP_VAL(0x03, 3, idx, | ||
8032 | HDA_OUTPUT)); | ||
8033 | if (err < 0) | ||
8034 | return err; | ||
8035 | } else | ||
8036 | return -1; | ||
8037 | sprintf(name, "%s Playback Switch", ctlname); | ||
8038 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
8039 | HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); | ||
8040 | if (err < 0) | ||
8041 | return err; | ||
8042 | return 0; | ||
8043 | } | ||
8044 | |||
8045 | /* add playback controls from the parsed DAC table */ | ||
8046 | static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, | ||
8047 | const struct auto_pin_cfg *cfg) | ||
8048 | { | ||
8049 | hda_nid_t nid; | ||
8050 | int err; | ||
8051 | |||
8052 | spec->multiout.num_dacs = 2; /* only use one dac */ | ||
8053 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
8054 | spec->multiout.dac_nids[0] = 2; | ||
8055 | spec->multiout.dac_nids[1] = 3; | ||
8056 | |||
8057 | nid = cfg->line_out_pins[0]; | ||
8058 | if (nid) | ||
8059 | alc268_new_analog_output(spec, nid, "Front", 0); | ||
8060 | |||
8061 | nid = cfg->speaker_pins[0]; | ||
8062 | if (nid == 0x1d) { | ||
8063 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
8064 | "Speaker Playback Volume", | ||
8065 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); | ||
8066 | if (err < 0) | ||
8067 | return err; | ||
8068 | } | ||
8069 | nid = cfg->hp_pins[0]; | ||
8070 | if (nid) | ||
8071 | alc268_new_analog_output(spec, nid, "Headphone", 0); | ||
8072 | |||
8073 | nid = cfg->line_out_pins[1] | cfg->line_out_pins[2]; | ||
8074 | if (nid == 0x16) { | ||
8075 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
8076 | "Mono Playback Switch", | ||
8077 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT)); | ||
8078 | if (err < 0) | ||
8079 | return err; | ||
8080 | } | ||
8081 | return 0; | ||
8082 | } | ||
8083 | |||
8084 | /* create playback/capture controls for input pins */ | ||
8085 | static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec, | ||
8086 | const struct auto_pin_cfg *cfg) | ||
8087 | { | ||
8088 | struct hda_input_mux *imux = &spec->private_imux; | ||
8089 | int i, idx1; | ||
8090 | |||
8091 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
8092 | switch(cfg->input_pins[i]) { | ||
8093 | case 0x18: | ||
8094 | idx1 = 0; /* Mic 1 */ | ||
8095 | break; | ||
8096 | case 0x19: | ||
8097 | idx1 = 1; /* Mic 2 */ | ||
8098 | break; | ||
8099 | case 0x1a: | ||
8100 | idx1 = 2; /* Line In */ | ||
8101 | break; | ||
8102 | case 0x1c: | ||
8103 | idx1 = 3; /* CD */ | ||
8104 | break; | ||
8105 | default: | ||
8106 | continue; | ||
8107 | } | ||
8108 | imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; | ||
8109 | imux->items[imux->num_items].index = idx1; | ||
8110 | imux->num_items++; | ||
8111 | } | ||
8112 | return 0; | ||
8113 | } | ||
8114 | |||
8115 | static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) | ||
8116 | { | ||
8117 | struct alc_spec *spec = codec->spec; | ||
8118 | hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0]; | ||
8119 | hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; | ||
8120 | hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; | ||
8121 | unsigned int dac_vol1, dac_vol2; | ||
8122 | |||
8123 | if (speaker_nid) { | ||
8124 | snd_hda_codec_write(codec, speaker_nid, 0, | ||
8125 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
8126 | snd_hda_codec_write(codec, 0x0f, 0, | ||
8127 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
8128 | AMP_IN_UNMUTE(1)); | ||
8129 | snd_hda_codec_write(codec, 0x10, 0, | ||
8130 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
8131 | AMP_IN_UNMUTE(1)); | ||
8132 | } else { | ||
8133 | snd_hda_codec_write(codec, 0x0f, 0, | ||
8134 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)); | ||
8135 | snd_hda_codec_write(codec, 0x10, 0, | ||
8136 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)); | ||
8137 | } | ||
8138 | |||
8139 | dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */ | ||
8140 | if (line_nid == 0x14) | ||
8141 | dac_vol2 = AMP_OUT_ZERO; | ||
8142 | else if (line_nid == 0x15) | ||
8143 | dac_vol1 = AMP_OUT_ZERO; | ||
8144 | if (hp_nid == 0x14) | ||
8145 | dac_vol2 = AMP_OUT_ZERO; | ||
8146 | else if (hp_nid == 0x15) | ||
8147 | dac_vol1 = AMP_OUT_ZERO; | ||
8148 | if (line_nid != 0x16 || hp_nid != 0x16 || | ||
8149 | spec->autocfg.line_out_pins[1] != 0x16 || | ||
8150 | spec->autocfg.line_out_pins[2] != 0x16) | ||
8151 | dac_vol1 = dac_vol2 = AMP_OUT_ZERO; | ||
8152 | |||
8153 | snd_hda_codec_write(codec, 0x02, 0, | ||
8154 | AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1); | ||
8155 | snd_hda_codec_write(codec, 0x03, 0, | ||
8156 | AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2); | ||
8157 | } | ||
8158 | |||
8159 | /* pcm configuration: identiacal with ALC880 */ | ||
8160 | #define alc268_pcm_analog_playback alc880_pcm_analog_playback | ||
8161 | #define alc268_pcm_analog_capture alc880_pcm_analog_capture | ||
8162 | #define alc268_pcm_digital_playback alc880_pcm_digital_playback | ||
8163 | |||
8164 | /* | ||
8165 | * BIOS auto configuration | ||
8166 | */ | ||
8167 | static int alc268_parse_auto_config(struct hda_codec *codec) | ||
8168 | { | ||
8169 | struct alc_spec *spec = codec->spec; | ||
8170 | int err; | ||
8171 | static hda_nid_t alc268_ignore[] = { 0 }; | ||
8172 | |||
8173 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
8174 | alc268_ignore); | ||
8175 | if (err < 0) | ||
8176 | return err; | ||
8177 | if (!spec->autocfg.line_outs) | ||
8178 | return 0; /* can't find valid BIOS pin config */ | ||
8179 | |||
8180 | err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
8181 | if (err < 0) | ||
8182 | return err; | ||
8183 | err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
8184 | if (err < 0) | ||
8185 | return err; | ||
8186 | |||
8187 | spec->multiout.max_channels = 2; | ||
8188 | |||
8189 | /* digital only support output */ | ||
8190 | if (spec->autocfg.dig_out_pin) | ||
8191 | spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; | ||
8192 | |||
8193 | if (spec->kctl_alloc) | ||
8194 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
8195 | |||
8196 | spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs; | ||
8197 | spec->num_mux_defs = 1; | ||
8198 | spec->input_mux = &spec->private_imux; | ||
8199 | |||
8200 | return 1; | ||
8201 | } | ||
8202 | |||
8203 | #define alc268_auto_init_multi_out alc882_auto_init_multi_out | ||
8204 | #define alc268_auto_init_hp_out alc882_auto_init_hp_out | ||
8205 | #define alc268_auto_init_analog_input alc882_auto_init_analog_input | ||
8206 | |||
8207 | /* init callback for auto-configuration model -- overriding the default init */ | ||
8208 | static void alc268_auto_init(struct hda_codec *codec) | ||
8209 | { | ||
8210 | alc268_auto_init_multi_out(codec); | ||
8211 | alc268_auto_init_hp_out(codec); | ||
8212 | alc268_auto_init_mono_speaker_out(codec); | ||
8213 | alc268_auto_init_analog_input(codec); | ||
8214 | } | ||
8215 | |||
8216 | /* | ||
8217 | * configuration and preset | ||
8218 | */ | ||
8219 | static const char *alc268_models[ALC268_MODEL_LAST] = { | ||
8220 | [ALC268_3ST] = "3stack", | ||
8221 | [ALC268_AUTO] = "auto", | ||
8222 | }; | ||
8223 | |||
8224 | static struct snd_pci_quirk alc268_cfg_tbl[] = { | ||
8225 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), | ||
8226 | {} | ||
8227 | }; | ||
8228 | |||
8229 | static struct alc_config_preset alc268_presets[] = { | ||
8230 | [ALC268_3ST] = { | ||
8231 | .mixers = { alc268_base_mixer, alc268_capture_alt_mixer }, | ||
8232 | .init_verbs = { alc268_base_init_verbs }, | ||
8233 | .num_dacs = ARRAY_SIZE(alc268_dac_nids), | ||
8234 | .dac_nids = alc268_dac_nids, | ||
8235 | .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), | ||
8236 | .adc_nids = alc268_adc_nids_alt, | ||
8237 | .hp_nid = 0x03, | ||
8238 | .dig_out_nid = ALC268_DIGOUT_NID, | ||
8239 | .num_channel_mode = ARRAY_SIZE(alc268_modes), | ||
8240 | .channel_mode = alc268_modes, | ||
8241 | .input_mux = &alc268_capture_source, | ||
8242 | }, | ||
8243 | }; | ||
8244 | |||
8245 | static int patch_alc268(struct hda_codec *codec) | ||
8246 | { | ||
8247 | struct alc_spec *spec; | ||
8248 | int board_config; | ||
8249 | int err; | ||
8250 | |||
8251 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
8252 | if (spec == NULL) | ||
8253 | return -ENOMEM; | ||
8254 | |||
8255 | codec->spec = spec; | ||
8256 | |||
8257 | board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST, | ||
8258 | alc268_models, | ||
8259 | alc268_cfg_tbl); | ||
8260 | |||
8261 | if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { | ||
8262 | printk(KERN_INFO "hda_codec: Unknown model for ALC268, " | ||
8263 | "trying auto-probe from BIOS...\n"); | ||
8264 | board_config = ALC268_AUTO; | ||
8265 | } | ||
8266 | |||
8267 | if (board_config == ALC268_AUTO) { | ||
8268 | /* automatic parse from the BIOS config */ | ||
8269 | err = alc268_parse_auto_config(codec); | ||
8270 | if (err < 0) { | ||
8271 | alc_free(codec); | ||
8272 | return err; | ||
8273 | } else if (!err) { | ||
8274 | printk(KERN_INFO | ||
8275 | "hda_codec: Cannot set up configuration " | ||
8276 | "from BIOS. Using base mode...\n"); | ||
8277 | board_config = ALC268_3ST; | ||
8278 | } | ||
8279 | } | ||
8280 | |||
8281 | if (board_config != ALC268_AUTO) | ||
8282 | setup_preset(spec, &alc268_presets[board_config]); | ||
8283 | |||
8284 | spec->stream_name_analog = "ALC268 Analog"; | ||
8285 | spec->stream_analog_playback = &alc268_pcm_analog_playback; | ||
8286 | spec->stream_analog_capture = &alc268_pcm_analog_capture; | ||
8287 | |||
8288 | spec->stream_name_digital = "ALC268 Digital"; | ||
8289 | spec->stream_digital_playback = &alc268_pcm_digital_playback; | ||
8290 | |||
8291 | if (board_config == ALC268_AUTO) { | ||
8292 | if (!spec->adc_nids && spec->input_mux) { | ||
8293 | /* check whether NID 0x07 is valid */ | ||
8294 | unsigned int wcap = get_wcaps(codec, 0x07); | ||
8295 | |||
8296 | /* get type */ | ||
8297 | wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||
8298 | if (wcap != AC_WID_AUD_IN) { | ||
8299 | spec->adc_nids = alc268_adc_nids_alt; | ||
8300 | spec->num_adc_nids = | ||
8301 | ARRAY_SIZE(alc268_adc_nids_alt); | ||
8302 | spec->mixers[spec->num_mixers] = | ||
8303 | alc268_capture_alt_mixer; | ||
8304 | spec->num_mixers++; | ||
8305 | } else { | ||
8306 | spec->adc_nids = alc268_adc_nids; | ||
8307 | spec->num_adc_nids = | ||
8308 | ARRAY_SIZE(alc268_adc_nids); | ||
8309 | spec->mixers[spec->num_mixers] = | ||
8310 | alc268_capture_mixer; | ||
8311 | spec->num_mixers++; | ||
8312 | } | ||
8313 | } | ||
8314 | } | ||
8315 | codec->patch_ops = alc_patch_ops; | ||
8316 | if (board_config == ALC268_AUTO) | ||
8317 | spec->init_hook = alc268_auto_init; | ||
8318 | |||
8319 | return 0; | ||
8320 | } | ||
8321 | |||
8322 | /* | ||
7807 | * ALC861 channel source setting (2/6 channel selection for 3-stack) | 8323 | * ALC861 channel source setting (2/6 channel selection for 3-stack) |
7808 | */ | 8324 | */ |
7809 | 8325 | ||
@@ -10728,6 +11244,7 @@ static int patch_alc662(struct hda_codec *codec) | |||
10728 | struct hda_codec_preset snd_hda_preset_realtek[] = { | 11244 | struct hda_codec_preset snd_hda_preset_realtek[] = { |
10729 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, | 11245 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, |
10730 | { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, | 11246 | { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, |
11247 | { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 }, | ||
10731 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", | 11248 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", |
10732 | .patch = patch_alc861 }, | 11249 | .patch = patch_alc861 }, |
10733 | { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, | 11250 | { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, |