/* * ALC260 quirk models * included by patch_realtek.c */ /* ALC260 models */ enum { ALC260_AUTO, ALC260_BASIC, ALC260_HP, ALC260_HP_DC7600, ALC260_HP_3013, ALC260_FUJITSU_S702X, ALC260_ACER, ALC260_WILL, ALC260_REPLACER_672V, ALC260_FAVORIT100, #ifdef CONFIG_SND_DEBUG ALC260_TEST, #endif ALC260_MODEL_LAST /* last tag */ }; static const hda_nid_t alc260_dac_nids[1] = { /* front */ 0x02, }; static const hda_nid_t alc260_adc_nids[1] = { /* ADC0 */ 0x04, }; static const hda_nid_t alc260_adc_nids_alt[1] = { /* ADC1 */ 0x05, }; /* NIDs used when simultaneous access to both ADCs makes sense. Note that * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. */ static const hda_nid_t alc260_dual_adc_nids[2] = { /* ADC0, ADC1 */ 0x04, 0x05 }; #define ALC260_DIGOUT_NID 0x03 #define ALC260_DIGIN_NID 0x06 static const struct hda_input_mux alc260_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, { "Front Mic", 0x1 }, { "Line", 0x2 }, { "CD", 0x4 }, }, }; /* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, * headphone jack and the internal CD lines since these are the only pins at * which audio can appear. For flexibility, also allow the option of * recording the mixer output on the second ADC (ADC0 doesn't have a * connection to the mixer output). */ static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = { { .num_items = 3, .items = { { "Mic/Line", 0x0 }, { "CD", 0x4 }, { "Headphone", 0x2 }, }, }, { .num_items = 4, .items = { { "Mic/Line", 0x0 }, { "CD", 0x4 }, { "Headphone", 0x2 }, { "Mixer", 0x5 }, }, }, }; /* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to * the Fujitsu S702x, but jacks are marked differently. */ static const struct hda_input_mux alc260_acer_capture_sources[2] = { { .num_items = 4, .items = { { "Mic", 0x0 }, { "Line", 0x2 }, { "CD", 0x4 }, { "Headphone", 0x5 }, }, }, { .num_items = 5, .items = { { "Mic", 0x0 }, { "Line", 0x2 }, { "CD", 0x4 }, { "Headphone", 0x6 }, { "Mixer", 0x5 }, }, }, }; /* Maxdata Favorit 100XS */ static const struct hda_input_mux alc260_favorit100_capture_sources[2] = { { .num_items = 2, .items = { { "Line/Mic", 0x0 }, { "CD", 0x4 }, }, }, { .num_items = 3, .items = { { "Line/Mic", 0x0 }, { "CD", 0x4 }, { "Mixer", 0x5 }, }, }, }; /* * 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 * element which allows changing the channel mode, so the verb list is * never used. */ static const struct hda_channel_mode alc260_modes[1] = { { 2, NULL }, }; /* Mixer combinations * * basic: base_output + input + pc_beep + capture * HP: base_output + input + capture_alt * HP_3013: hp_3013 + input + capture * fujitsu: fujitsu + capture * acer: acer + capture */ static const struct snd_kcontrol_new alc260_base_output_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), { } /* end */ }; static const struct snd_kcontrol_new alc260_input_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), { } /* end */ }; /* update HP, line and mono out pins according to the master switch */ static void alc260_hp_master_update(struct hda_codec *codec) { update_speakers(codec); } static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; *ucontrol->value.integer.value = !spec->master_mute; return 0; } static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; int val = !*ucontrol->value.integer.value; if (val == spec->master_mute) return 0; spec->master_mute = val; alc260_hp_master_update(codec); return 1; } static const struct snd_kcontrol_new alc260_hp_output_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, }, HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT), { } /* end */ }; static const struct hda_verb alc260_hp_unsol_verbs[] = { {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {}, }; static void alc260_hp_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x0f; spec->autocfg.speaker_pins[0] = 0x10; spec->autocfg.speaker_pins[1] = 0x11; spec->automute = 1; spec->automute_mode = ALC_AUTOMUTE_PIN; } static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, }, HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), { } /* end */ }; static void alc260_hp_3013_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x10; spec->autocfg.speaker_pins[1] = 0x11; spec->automute = 1; spec->automute_mode = ALC_AUTOMUTE_PIN; } static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT), 0 }, }; static const struct hda_bind_ctls alc260_dc7600_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), 0 }, }; static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol), HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch), HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), { } /* end */ }; static const struct hda_verb alc260_hp_3013_unsol_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {}, }; static void alc260_hp_3012_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x10; spec->autocfg.speaker_pins[0] = 0x0f; spec->autocfg.speaker_pins[1] = 0x11; spec->autocfg.speaker_pins[2] = 0x15; spec->automute = 1; spec->automute_mode = ALC_AUTOMUTE_PIN; } /* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. */ static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT), 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), ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT), { } /* end */ }; /* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current * versions of the ALC260 don't act on requests to enable mic bias from NID * 0x0f (used to drive the headphone jack in these laptops). The ALC260 * datasheet doesn't mention this restriction. At this stage it's not clear * whether this behaviour is intentional or is a hardware bug in chip * revisions available in early 2006. Therefore for now allow the * "Headphone Jack Mode" control to span all choices, but if it turns out * that the lack of mic bias for this NID is intentional we could change the * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. * * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006 * don't appear to make the mic bias available from the "line" jack, even * though the NID used for this jack (0x14) can supply it. The theory is * that perhaps Acer have included blocking capacitors between the ALC260 * and the output jack. If this turns out to be the case for all such * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT * to ALC_PIN_DIR_INOUT_NOMICBIAS. * * The C20x Tablet series have a mono internal speaker which is controlled * via the chip's Mono sum widget and pin complex, so include the necessary * controls for such models. On models without a "mono speaker" the control * won't do anything. */ static const struct snd_kcontrol_new alc260_acer_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), { } /* end */ }; /* Maxdata Favorit 100XS: one output and one input (0x12) jack */ static const struct snd_kcontrol_new alc260_favorit100_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT), ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), { } /* end */ }; /* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12, * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17. */ static const struct snd_kcontrol_new alc260_will_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), { } /* end */ }; /* Replacer 672V ALC260 pin usage: Mic jack = 0x12, * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f. */ static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT), HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), { } /* end */ }; /* * initialization verbs */ static const struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic2 (front panel) pin widget for input and vref at 80% */ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* LINE-2 is used for line-out in rear */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* select line-out */ {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, /* LINE-OUT pin */ {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* enable HP */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* enable Mono */ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* mute capture amp left and right */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to line in (default select for this ADC) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mute capture amp left and right */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to line in (default select for this ADC) */ {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, /* set vol=0 Line-Out mixer amp left and right */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* unmute pin widget amp left and right (no gain on this amp) */ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* set vol=0 HP mixer amp left and right */ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* unmute pin widget amp left and right (no gain on this amp) */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* set vol=0 Mono mixer amp left and right */ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* unmute pin widget amp left and right (no gain on this amp) */ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* unmute LINE-2 out pin */ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ /* mute analog inputs */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* mute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mute Headphone out path */ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mute Mono out path */ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, { } }; #if 0 /* should be identical with alc260_init_verbs? */ static const struct hda_verb alc260_hp_init_verbs[] = { /* Headphone and output */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, /* mono output */ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* Mic2 (front panel) pin widget for input and vref at 80% */ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, /* Line-2 pin widget for output */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* CD pin widget for input */ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, /* unmute amp left and right */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, /* set connection select to line in (default select for this ADC) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, /* unmute Line-Out mixer amp left and right (volume = 0) */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, /* mute pin widget amp left and right (no gain on this amp) */ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, /* unmute HP mixer amp left and right (volume = 0) */ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, /* mute pin widget amp left and right (no gain on this amp) */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ /* mute analog inputs */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /* Unmute Headphone out path */ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /* Unmute Mono out path */ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, { } }; #endif static const struct hda_verb alc260_hp_3013_init_verbs[] = { /* Line out and output */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* mono output */ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* Mic2 (front panel) pin widget for input and vref at 80% */ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, /* Headphone pin widget for output */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, /* CD pin widget for input */ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, /* unmute amp left and right */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, /* set connection select to line in (default select for this ADC) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, /* unmute Line-Out mixer amp left and right (volume = 0) */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, /* mute pin widget amp left and right (no gain on this amp) */ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, /* unmute HP mixer amp left and right (volume = 0) */ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, /* mute pin widget amp left and right (no gain on this amp) */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ /* mute analog inputs */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /* Unmute Headphone out path */ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /* Unmute Mono out path */ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, { } }; /* Initialisation sequence for ALC260 as configured in Fujitsu S702x * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD * audio = 0x16, internal speaker = 0x10. */ static const 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. */ {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)}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x15, 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}, /* Ensure Line1 pin widget takes its input from the OUT1 sum bus * when acting as an output. */ {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, /* Start with output sum widgets muted and their output gains at min */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* 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 output buffer since it starts as an output. * If the pin mode is changed by the user the pin mode control will * take care of enabling the pin's input/output buffers as needed. * Therefore there's no need to enable the input buffer at this * stage. */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Unmute input buffer of 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 match default mixer setting - line * in (on mic1 pin) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Do the same for the second ADC: mute capture input amp and * set ADC connection to line in (on mic1 pin) */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x05, 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 */ { } }; /* Initialisation sequence for ALC260 as configured in Acer TravelMate and * similar laptops (adapted from Fujitsu init verbs). */ static const struct hda_verb alc260_acer_init_verbs[] = { /* On TravelMate laptops, GPIO 0 enables the internal speaker and * the headphone jack. Turn this on and rely on the standard mute * methods whenever the user wants to turn these outputs off. */ {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, /* Internal speaker/Headphone jack is connected to Line-out pin */ {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Internal microphone/Mic jack is connected to Mic1 pin */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, /* Line In jack is connected to Line1 pin */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Ensure all other unused pins are disabled and muted. */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x10, 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)}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x15, 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}, /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum * bus when acting as outputs. */ {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, /* Start with output sum widgets muted and their output gains at min */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* Unmute Line-out pin widget amp left and right * (no equiv mixer ctrl) */ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Unmute Mic1 and Line1 pin widget input buffers since they start as * inputs. If the pin mode is changed by the user the pin mode control * will take care of enabling the pin's input/output buffers as needed. * Therefore there's no need to enable the input buffer at this * stage. */ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x14, 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 match default mixer setting - mic * (on mic1 pin) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Do similar with the second ADC: mute capture input amp and * set ADC connection to mic to match ALSA's default state. */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x05, 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 */ { } }; /* Initialisation sequence for Maxdata Favorit 100XS * (adapted from Acer init verbs). */ static const struct hda_verb alc260_favorit100_init_verbs[] = { /* GPIO 0 enables the output jack. * Turn this on and rely on the standard mute * methods whenever the user wants to turn these outputs off. */ {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, /* Line/Mic input jack is connected to Mic1 pin */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, /* Ensure all other unused pins are disabled and muted. */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x10, 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)}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x15, 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}, /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum * bus when acting as outputs. */ {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, /* Start with output sum widgets muted and their output gains at min */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* Unmute Line-out pin widget amp left and right * (no equiv mixer ctrl) */ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Unmute Mic1 and Line1 pin widget input buffers since they start as * inputs. If the pin mode is changed by the user the pin mode control * will take care of enabling the pin's input/output buffers as needed. * Therefore there's no need to enable the input buffer at this * stage. */ {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 match default mixer setting - mic * (on mic1 pin) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Do similar with the second ADC: mute capture input amp and * set ADC connection to mic to match ALSA's default state. */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x05, 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 const struct hda_verb alc260_will_verbs[] = { {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, {0x1a, AC_VERB_SET_PROC_COEF, 0x3040}, {} }; static const struct hda_verb alc260_replacer_672v_verbs[] = { {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, {0x1a, AC_VERB_SET_PROC_COEF, 0x3050}, {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {} }; /* toggle speaker-output according to the hp-jack state */ static void alc260_replacer_672v_automute(struct hda_codec *codec) { unsigned int present; /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */ present = snd_hda_jack_detect(codec, 0x0f); if (present) { snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1); snd_hda_codec_write_cache(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); } else { snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); snd_hda_codec_write_cache(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); } } static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, unsigned int res) { if ((res >> 26) == ALC_HP_EVENT) alc260_replacer_672v_automute(codec); } static const struct hda_verb alc260_hp_dc7600_verbs[] = { {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {} }; /* Test configuration for debugging, modelled after the ALC880 test * configuration. */ #ifdef CONFIG_SND_DEBUG static const hda_nid_t alc260_test_dac_nids[1] = { 0x02, }; static const hda_nid_t alc260_test_adc_nids[2] = { 0x04, 0x05, }; /* For testing the ALC260, each input MUX needs its own definition since * the signal assignments are different. This assumes that the first ADC * is NID 0x04. */ static const struct hda_input_mux alc260_test_capture_sources[2] = { { .num_items = 7, .items = { { "MIC1 pin", 0x0 }, { "MIC2 pin", 0x1 }, { "LINE1 pin", 0x2 }, { "LINE2 pin", 0x3 }, { "CD pin", 0x4 }, { "LINE-OUT pin", 0x5 }, { "HP-OUT pin", 0x6 }, }, }, { .num_items = 8, .items = { { "MIC1 pin", 0x0 }, { "MIC2 pin", 0x1 }, { "LINE1 pin", 0x2 }, { "LINE2 pin", 0x3 }, { "CD pin", 0x4 }, { "Mixer", 0x5 }, { "LINE-OUT pin", 0x6 }, { "HP-OUT pin", 0x7 }, }, }, }; static const struct snd_kcontrol_new alc260_test_mixer[] = { /* Output driver widgets */ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT), HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), /* Modes for retasking pin widgets * Note: the ALC260 doesn't seem to act on requests to enable mic * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't * mention this restriction. At this stage it's not clear whether * this behaviour is intentional or is a hardware bug in chip * revisions available at least up until early 2006. Therefore for * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all * choices, but if it turns out that the lack of mic bias for these * NIDs is intentional we could change their modes from * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. */ ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT), ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT), ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT), /* Loopback mixer controls */ HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT), HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT), HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT), HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT), HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT), /* Controls for GPIO pins, assuming they are configured as outputs */ ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), /* Switches to allow the digital IO pins to be enabled. The datasheet * is ambigious as to which NID is which; testing on laptops which * make this output available should provide clarification. */ ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), /* A switch allowing EAPD to be enabled. Some laptops seem to use * this output to turn on an external amplifier. */ ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), { } /* end */ }; static const struct hda_verb alc260_test_init_verbs[] = { /* Enable all GPIOs as outputs with an initial value of 0 */ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, /* Enable retasking pins as output, initially without power amp */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Disable digital (SPDIF) pins initially, but users can enable * them via a mixer switch. In the case of SPDIF-out, this initverb * payload also sets the generation to 0, output to be in "consumer" * PCM format, copyright asserted, no pre-emphasis and no validity * control. */ {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the * OUT1 sum bus when acting as an output. */ {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, {0x0c, AC_VERB_SET_CONNECT_SEL, 0}, {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, {0x0e, AC_VERB_SET_CONNECT_SEL, 0}, /* Start with output sum widgets muted and their output gains at min */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* Unmute retasking pin widget output buffers since the default * state appears to be output. As the pin mode is changed by the * user the pin mode control will take care of enabling the pin's * input/output buffers as needed. */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Also unmute the mono-out pin widget */ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mute capture amp left and right */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Set ADC connection select to match default mixer setting (mic1 * pin) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Do the same for the second ADC: mute capture input amp and * set ADC connection to mic1 pin */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x05, 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 */ { } }; #endif /* * ALC260 configurations */ static const char * const alc260_models[ALC260_MODEL_LAST] = { [ALC260_BASIC] = "basic", [ALC260_HP] = "hp", [ALC260_HP_3013] = "hp-3013", [ALC260_HP_DC7600] = "hp-dc7600", [ALC260_FUJITSU_S702X] = "fujitsu", [ALC260_ACER] = "acer", [ALC260_WILL] = "will", [ALC260_REPLACER_672V] = "replacer", [ALC260_FAVORIT100] = "favorit100", #ifdef CONFIG_SND_DEBUG [ALC260_TEST] = "test", #endif [ALC260_AUTO] = "auto", }; static const struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */ SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP), SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), {} }; static const struct alc_config_preset alc260_presets[] = { [ALC260_BASIC] = { .mixers = { alc260_base_output_mixer, alc260_input_mixer }, .init_verbs = { alc260_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, }, [ALC260_HP] = { .mixers = { alc260_hp_output_mixer, alc260_input_mixer }, .init_verbs = { alc260_init_verbs, alc260_hp_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), .adc_nids = alc260_adc_nids_alt, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, .unsol_event = alc_sku_unsol_event, .setup = alc260_hp_setup, .init_hook = alc_inithook, }, [ALC260_HP_DC7600] = { .mixers = { alc260_hp_dc7600_mixer, alc260_input_mixer }, .init_verbs = { alc260_init_verbs, alc260_hp_dc7600_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), .adc_nids = alc260_adc_nids_alt, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, .unsol_event = alc_sku_unsol_event, .setup = alc260_hp_3012_setup, .init_hook = alc_inithook, }, [ALC260_HP_3013] = { .mixers = { alc260_hp_3013_mixer, alc260_input_mixer }, .init_verbs = { alc260_hp_3013_init_verbs, alc260_hp_3013_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), .adc_nids = alc260_adc_nids_alt, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, .unsol_event = alc_sku_unsol_event, .setup = alc260_hp_3013_setup, .init_hook = alc_inithook, }, [ALC260_FUJITSU_S702X] = { .mixers = { alc260_fujitsu_mixer }, .init_verbs = { alc260_fujitsu_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources), .input_mux = alc260_fujitsu_capture_sources, }, [ALC260_ACER] = { .mixers = { alc260_acer_mixer }, .init_verbs = { alc260_acer_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), .input_mux = alc260_acer_capture_sources, }, [ALC260_FAVORIT100] = { .mixers = { alc260_favorit100_mixer }, .init_verbs = { alc260_favorit100_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources), .input_mux = alc260_favorit100_capture_sources, }, [ALC260_WILL] = { .mixers = { alc260_will_mixer }, .init_verbs = { alc260_init_verbs, alc260_will_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), .adc_nids = alc260_adc_nids, .dig_out_nid = ALC260_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, }, [ALC260_REPLACER_672V] = { .mixers = { alc260_replacer_672v_mixer }, .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), .adc_nids = alc260_adc_nids, .dig_out_nid = ALC260_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, .unsol_event = alc260_replacer_672v_unsol_event, .init_hook = alc260_replacer_672v_automute, }, #ifdef CONFIG_SND_DEBUG [ALC260_TEST] = { .mixers = { alc260_test_mixer }, .init_verbs = { alc260_test_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), .dac_nids = alc260_test_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids), .adc_nids = alc260_test_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources), .input_mux = alc260_test_capture_sources, }, #endif };