Loading sound/pci/hda/patch_realtek.c +157 −3 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ enum { enum { ALC260_BASIC, ALC260_HP, ALC260_FUJITSU_S702x, ALC260_MODEL_LAST /* last tag */ }; Loading @@ -72,6 +73,7 @@ enum { #define PIN_VREF50 0x21 #define PIN_OUT 0x40 #define PIN_HP 0xc0 #define PIN_HP_AMP 0x80 struct alc_spec { /* codec parameterization */ Loading Loading @@ -284,6 +286,54 @@ static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u #define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) /* * Control of pin widget settings via the mixer. Only boolean settings are * supported, so VrefEn can't be controlled using these functions as they * stand. */ static int alc_pinctl_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0; } static int alc_pinctl_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = kcontrol->private_value & 0xffff; long mask = (kcontrol->private_value >> 16) & 0xff; long *valp = ucontrol->value.integer.value; *valp = 0; if (snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00) & mask) *valp = 1; return 0; } static int alc_pinctl_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = kcontrol->private_value & 0xffff; long mask = (kcontrol->private_value >> 16) & 0xff; long *valp = ucontrol->value.integer.value; unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00); int change = ((pinctl & mask)!=0) != *valp; if (change) snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, *valp?(pinctl|mask):(pinctl&~mask)); return change; } #define ALC_PINCTL_SWITCH(xname, nid, mask) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ .info = alc_pinctl_switch_info, \ .get = alc_pinctl_switch_get, \ .put = alc_pinctl_switch_put, \ .private_value = (nid) | (mask<<16) } /* * ALC880 3-stack model Loading Loading @@ -2205,6 +2255,17 @@ static struct hda_input_mux alc260_capture_source = { }, }; /* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack * and the internal CD lines. */ static struct hda_input_mux alc260_fujitsu_capture_source = { .num_items = 2, .items = { { "Mic/Line", 0x0 }, { "CD", 0x4 }, }, }; /* * This is just place-holder, so there's something for alc_build_pcms to look * at when it calculates the maximum number of channels. ALC260 has no mixer Loading Loading @@ -2271,6 +2332,30 @@ static snd_kcontrol_new_t alc260_hp_mixer[] = { { } /* end */ }; static snd_kcontrol_new_t alc260_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), ALC_PINCTL_SWITCH("Headphone Amp Switch", 0x14, PIN_HP_AMP), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = alc_mux_enum_info, .get = alc_mux_enum_get, .put = alc_mux_enum_put, }, { } /* end */ }; static struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, Loading Loading @@ -2332,6 +2417,60 @@ static struct hda_verb alc260_init_verbs[] = { { } }; /* Initialisation sequence for ALC260 as configured in Fujitsu S702x * laptops. */ static struct hda_verb alc260_fujitsu_init_verbs[] = { /* Disable all GPIOs */ {0x01, AC_VERB_SET_GPIO_MASK, 0}, /* Internal speaker is connected to headphone pin */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Headphone/Line-out jack connects to Line1 pin; make it an output */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Ensure all other unused pins are disabled and muted. * Note: trying to set widget 0x15 to anything blocks all audio * output for some reason, so just leave that at the default. */ {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Disable digital (SPDIF) pins */ {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, /* Start with mixer outputs muted */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Unmute pin widget used for Line-in (no equiv mixer ctrl) */ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* Mute capture amp left and right */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Set ADC connection select to line in (on mic1 pin) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Mute all inputs to mixer widget (even unconnected ones) */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ }; static struct hda_pcm_stream alc260_pcm_analog_playback = { .substreams = 1, .channels_min = 2, Loading @@ -2347,6 +2486,8 @@ static struct hda_pcm_stream alc260_pcm_analog_capture = { static struct hda_board_config alc260_cfg_tbl[] = { { .modelname = "hp", .config = ALC260_HP }, { .pci_subvendor = 0x103c, .config = ALC260_HP }, { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702x }, { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702x }, {} }; Loading @@ -2373,14 +2514,23 @@ static int patch_alc260(struct hda_codec *codec) spec->mixers[spec->num_mixers] = alc260_hp_mixer; spec->num_mixers++; break; case ALC260_FUJITSU_S702x: spec->mixers[spec->num_mixers] = alc260_fujitsu_mixer; spec->num_mixers++; break; default: spec->mixers[spec->num_mixers] = alc260_base_mixer; spec->num_mixers++; break; } if (board_config != ALC260_FUJITSU_S702x) { spec->init_verbs[0] = alc260_init_verbs; spec->num_init_verbs = 1; } else { spec->init_verbs[0] = alc260_fujitsu_init_verbs; spec->num_init_verbs = 1; } spec->channel_mode = alc260_modes; spec->num_channel_mode = ARRAY_SIZE(alc260_modes); Loading @@ -2393,7 +2543,11 @@ static int patch_alc260(struct hda_codec *codec) spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids); spec->multiout.dac_nids = alc260_dac_nids; if (board_config != ALC260_FUJITSU_S702x) { spec->input_mux = &alc260_capture_source; } else { spec->input_mux = &alc260_fujitsu_capture_source; } switch (board_config) { case ALC260_HP: spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); Loading Loading
sound/pci/hda/patch_realtek.c +157 −3 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ enum { enum { ALC260_BASIC, ALC260_HP, ALC260_FUJITSU_S702x, ALC260_MODEL_LAST /* last tag */ }; Loading @@ -72,6 +73,7 @@ enum { #define PIN_VREF50 0x21 #define PIN_OUT 0x40 #define PIN_HP 0xc0 #define PIN_HP_AMP 0x80 struct alc_spec { /* codec parameterization */ Loading Loading @@ -284,6 +286,54 @@ static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u #define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) /* * Control of pin widget settings via the mixer. Only boolean settings are * supported, so VrefEn can't be controlled using these functions as they * stand. */ static int alc_pinctl_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0; } static int alc_pinctl_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = kcontrol->private_value & 0xffff; long mask = (kcontrol->private_value >> 16) & 0xff; long *valp = ucontrol->value.integer.value; *valp = 0; if (snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00) & mask) *valp = 1; return 0; } static int alc_pinctl_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = kcontrol->private_value & 0xffff; long mask = (kcontrol->private_value >> 16) & 0xff; long *valp = ucontrol->value.integer.value; unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00); int change = ((pinctl & mask)!=0) != *valp; if (change) snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, *valp?(pinctl|mask):(pinctl&~mask)); return change; } #define ALC_PINCTL_SWITCH(xname, nid, mask) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ .info = alc_pinctl_switch_info, \ .get = alc_pinctl_switch_get, \ .put = alc_pinctl_switch_put, \ .private_value = (nid) | (mask<<16) } /* * ALC880 3-stack model Loading Loading @@ -2205,6 +2255,17 @@ static struct hda_input_mux alc260_capture_source = { }, }; /* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack * and the internal CD lines. */ static struct hda_input_mux alc260_fujitsu_capture_source = { .num_items = 2, .items = { { "Mic/Line", 0x0 }, { "CD", 0x4 }, }, }; /* * This is just place-holder, so there's something for alc_build_pcms to look * at when it calculates the maximum number of channels. ALC260 has no mixer Loading Loading @@ -2271,6 +2332,30 @@ static snd_kcontrol_new_t alc260_hp_mixer[] = { { } /* end */ }; static snd_kcontrol_new_t alc260_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), ALC_PINCTL_SWITCH("Headphone Amp Switch", 0x14, PIN_HP_AMP), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = alc_mux_enum_info, .get = alc_mux_enum_get, .put = alc_mux_enum_put, }, { } /* end */ }; static struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, Loading Loading @@ -2332,6 +2417,60 @@ static struct hda_verb alc260_init_verbs[] = { { } }; /* Initialisation sequence for ALC260 as configured in Fujitsu S702x * laptops. */ static struct hda_verb alc260_fujitsu_init_verbs[] = { /* Disable all GPIOs */ {0x01, AC_VERB_SET_GPIO_MASK, 0}, /* Internal speaker is connected to headphone pin */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Headphone/Line-out jack connects to Line1 pin; make it an output */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Ensure all other unused pins are disabled and muted. * Note: trying to set widget 0x15 to anything blocks all audio * output for some reason, so just leave that at the default. */ {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Disable digital (SPDIF) pins */ {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, /* Start with mixer outputs muted */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Unmute pin widget used for Line-in (no equiv mixer ctrl) */ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* Mute capture amp left and right */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Set ADC connection select to line in (on mic1 pin) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Mute all inputs to mixer widget (even unconnected ones) */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ }; static struct hda_pcm_stream alc260_pcm_analog_playback = { .substreams = 1, .channels_min = 2, Loading @@ -2347,6 +2486,8 @@ static struct hda_pcm_stream alc260_pcm_analog_capture = { static struct hda_board_config alc260_cfg_tbl[] = { { .modelname = "hp", .config = ALC260_HP }, { .pci_subvendor = 0x103c, .config = ALC260_HP }, { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702x }, { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702x }, {} }; Loading @@ -2373,14 +2514,23 @@ static int patch_alc260(struct hda_codec *codec) spec->mixers[spec->num_mixers] = alc260_hp_mixer; spec->num_mixers++; break; case ALC260_FUJITSU_S702x: spec->mixers[spec->num_mixers] = alc260_fujitsu_mixer; spec->num_mixers++; break; default: spec->mixers[spec->num_mixers] = alc260_base_mixer; spec->num_mixers++; break; } if (board_config != ALC260_FUJITSU_S702x) { spec->init_verbs[0] = alc260_init_verbs; spec->num_init_verbs = 1; } else { spec->init_verbs[0] = alc260_fujitsu_init_verbs; spec->num_init_verbs = 1; } spec->channel_mode = alc260_modes; spec->num_channel_mode = ARRAY_SIZE(alc260_modes); Loading @@ -2393,7 +2543,11 @@ static int patch_alc260(struct hda_codec *codec) spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids); spec->multiout.dac_nids = alc260_dac_nids; if (board_config != ALC260_FUJITSU_S702x) { spec->input_mux = &alc260_capture_source; } else { spec->input_mux = &alc260_fujitsu_capture_source; } switch (board_config) { case ALC260_HP: spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); Loading