1
0
Fork 0

[ALSA] hda-codec - model for alc262 to support Lenovo 3000

This model is to support the Lenovo 3000 y410.
ALSA bug#3856:
	https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3856

Signed-off-by: Jiang zhe <zhe.jiang@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
wifi-calibration
Jiang zhe 2008-03-20 12:12:39 +01:00 committed by Takashi Iwai
parent 07bcb316cf
commit 0e31daf7d6
1 changed files with 100 additions and 0 deletions

View File

@ -98,6 +98,7 @@ enum {
ALC262_SONY_ASSAMD,
ALC262_BENQ_T31,
ALC262_ULTRA,
ALC262_LENOVO_3000,
ALC262_AUTO,
ALC262_MODEL_LAST /* last tag */
};
@ -8728,6 +8729,12 @@ static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
{}
};
static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{}
};
static struct hda_input_mux alc262_fujitsu_capture_source = {
.num_items = 3,
.items = {
@ -8808,6 +8815,46 @@ static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
},
};
/* mute/unmute internal speaker according to the hp jack and mute state */
static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
{
struct alc_spec *spec = codec->spec;
unsigned int mute;
if (force || !spec->sense_updated) {
unsigned int present_int_hp;
/* need to execute and sync at first */
snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
AC_VERB_GET_PIN_SENSE, 0);
spec->jack_present = (present_int_hp & 0x80000000) != 0;
spec->sense_updated = 1;
}
if (spec->jack_present) {
/* mute internal speaker */
snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
HDA_AMP_MUTE, HDA_AMP_MUTE);
snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
HDA_AMP_MUTE, HDA_AMP_MUTE);
} else {
/* unmute internal speaker if necessary */
mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
HDA_AMP_MUTE, mute);
snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
HDA_AMP_MUTE, mute);
}
}
/* unsolicited event for HP jack sensing */
static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
unsigned int res)
{
if ((res >> 26) != ALC_HP_EVENT)
return;
alc262_lenovo_3000_automute(codec, 1);
}
/* bind hp and internal speaker mute (with plug check) */
static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@ -8849,6 +8896,44 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
{ } /* end */
};
/* bind hp and internal speaker mute (with plug check) */
static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
long *valp = ucontrol->value.integer.value;
int change;
change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
HDA_AMP_MUTE,
valp ? 0 : HDA_AMP_MUTE);
if (change)
alc262_lenovo_3000_automute(codec, 0);
return change;
}
static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = alc262_lenovo_3000_master_sw_put,
.private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
},
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
/* additional init verbs for Benq laptops */
static struct hda_verb alc262_EAPD_verbs[] = {
{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
@ -9398,6 +9483,7 @@ static const char *alc262_models[ALC262_MODEL_LAST] = {
[ALC262_BENQ_T31] = "benq-t31",
[ALC262_SONY_ASSAMD] = "sony-assamd",
[ALC262_ULTRA] = "ultra",
[ALC262_LENOVO_3000] = "lenovo-3000",
[ALC262_AUTO] = "auto",
};
@ -9434,6 +9520,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
@ -9596,6 +9683,19 @@ static struct alc_config_preset alc262_presets[] = {
.unsol_event = alc262_ultra_unsol_event,
.init_hook = alc262_ultra_automute,
},
[ALC262_LENOVO_3000] = {
.mixers = { alc262_lenovo_3000_mixer },
.init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
alc262_lenovo_3000_unsol_verbs },
.num_dacs = ARRAY_SIZE(alc262_dac_nids),
.dac_nids = alc262_dac_nids,
.hp_nid = 0x03,
.dig_out_nid = ALC262_DIGOUT_NID,
.num_channel_mode = ARRAY_SIZE(alc262_modes),
.channel_mode = alc262_modes,
.input_mux = &alc262_fujitsu_capture_source,
.unsol_event = alc262_lenovo_3000_unsol_event,
},
};
static int patch_alc262(struct hda_codec *codec)