Commit 081a8c45 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'fix/hda' into topic/hda

parents 71623855 7085ec12
...@@ -209,6 +209,7 @@ AD1884A / AD1883 / AD1984A / AD1984B ...@@ -209,6 +209,7 @@ AD1884A / AD1883 / AD1984A / AD1984B
laptop laptop with HP jack sensing laptop laptop with HP jack sensing
mobile mobile devices with HP jack sensing mobile mobile devices with HP jack sensing
thinkpad Lenovo Thinkpad X300 thinkpad Lenovo Thinkpad X300
touchsmart HP Touchsmart
AD1884 AD1884
====== ======
......
...@@ -4031,6 +4031,127 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec) ...@@ -4031,6 +4031,127 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec)
return 0; return 0;
} }
/*
* HP Touchsmart
* port-A (0x11) - front hp-out
* port-B (0x14) - unused
* port-C (0x15) - unused
* port-D (0x12) - rear line out
* port-E (0x1c) - front mic-in
* port-F (0x16) - Internal speakers
* digital-mic (0x17) - Internal mic
*/
static struct hda_verb ad1984a_touchsmart_verbs[] = {
/* DACs; unmute as default */
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
/* Port-A (HP) mixer - route only from analog mixer */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
/* Port-A pin */
{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
/* Port-A (HP) pin - always unmuted */
{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Port-E (int speaker) mixer - route only from analog mixer */
{0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
/* Port-E pin */
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
/* Port-F (int speaker) mixer - route only from analog mixer */
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
/* Port-F pin */
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* Analog mixer; mute as default */
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
/* Analog Mix output amp */
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* capture sources */
/* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* unsolicited event for pin-sense */
{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
/* allow to touch GPIO1 (for mute control) */
{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
{0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
/* internal mic - dmic */
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
/* set magic COEFs for dmic */
{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
{0x01, AC_VERB_SET_PROC_COEF, 0x08},
{ } /* end */
};
static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
{
.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 = ad1884a_mobile_master_sw_put,
.private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
},
HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
{ } /* end */
};
/* switch to external mic if plugged */
static void ad1984a_touchsmart_automic(struct hda_codec *codec)
{
if (snd_hda_codec_read(codec, 0x1c, 0,
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000) {
snd_hda_codec_write(codec, 0x0c, 0,
AC_VERB_SET_CONNECT_SEL, 0x4);
} else {
snd_hda_codec_write(codec, 0x0c, 0,
AC_VERB_SET_CONNECT_SEL, 0x5);
}
}
/* unsolicited event for HP jack sensing */
static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
unsigned int res)
{
switch (res >> 26) {
case AD1884A_HP_EVENT:
ad1884a_hp_automute(codec);
break;
case AD1884A_MIC_EVENT:
ad1984a_touchsmart_automic(codec);
break;
}
}
/* initialize jack-sensing, too */
static int ad1984a_touchsmart_init(struct hda_codec *codec)
{
ad198x_init(codec);
ad1884a_hp_automute(codec);
ad1984a_touchsmart_automic(codec);
return 0;
}
/* /*
*/ */
...@@ -4039,6 +4160,7 @@ enum { ...@@ -4039,6 +4160,7 @@ enum {
AD1884A_LAPTOP, AD1884A_LAPTOP,
AD1884A_MOBILE, AD1884A_MOBILE,
AD1884A_THINKPAD, AD1884A_THINKPAD,
AD1984A_TOUCHSMART,
AD1884A_MODELS AD1884A_MODELS
}; };
...@@ -4047,6 +4169,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = { ...@@ -4047,6 +4169,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = {
[AD1884A_LAPTOP] = "laptop", [AD1884A_LAPTOP] = "laptop",
[AD1884A_MOBILE] = "mobile", [AD1884A_MOBILE] = "mobile",
[AD1884A_THINKPAD] = "thinkpad", [AD1884A_THINKPAD] = "thinkpad",
[AD1984A_TOUCHSMART] = "touchsmart",
}; };
static struct snd_pci_quirk ad1884a_cfg_tbl[] = { static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
...@@ -4059,6 +4182,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = { ...@@ -4059,6 +4182,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
{} {}
}; };
...@@ -4142,6 +4266,21 @@ static int patch_ad1884a(struct hda_codec *codec) ...@@ -4142,6 +4266,21 @@ static int patch_ad1884a(struct hda_codec *codec)
codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
codec->patch_ops.init = ad1984a_thinkpad_init; codec->patch_ops.init = ad1984a_thinkpad_init;
break; break;
case AD1984A_TOUCHSMART:
spec->mixers[0] = ad1984a_touchsmart_mixers;
spec->init_verbs[0] = ad1984a_touchsmart_verbs;
spec->multiout.dig_out_nid = 0;
codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
codec->patch_ops.init = ad1984a_touchsmart_init;
/* set the upper-limit for mixer amp to 0dB for avoiding the
* possible damage by overloading
*/
snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
(0x17 << AC_AMPCAP_OFFSET_SHIFT) |
(0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
(0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
(1 << AC_AMPCAP_MUTE_SHIFT));
break;
} }
return 0; return 0;
......
This diff is collapsed.
...@@ -182,8 +182,8 @@ struct sigmatel_jack { ...@@ -182,8 +182,8 @@ struct sigmatel_jack {
struct sigmatel_mic_route { struct sigmatel_mic_route {
hda_nid_t pin; hda_nid_t pin;
unsigned char mux_idx; signed char mux_idx;
unsigned char dmux_idx; signed char dmux_idx;
}; };
struct sigmatel_spec { struct sigmatel_spec {
...@@ -3469,18 +3469,26 @@ static int set_mic_route(struct hda_codec *codec, ...@@ -3469,18 +3469,26 @@ static int set_mic_route(struct hda_codec *codec,
break; break;
if (i <= AUTO_PIN_FRONT_MIC) { if (i <= AUTO_PIN_FRONT_MIC) {
/* analog pin */ /* analog pin */
mic->dmux_idx = 0;
i = get_connection_index(codec, spec->mux_nids[0], pin); i = get_connection_index(codec, spec->mux_nids[0], pin);
if (i < 0) if (i < 0)
return -1; return -1;
mic->mux_idx = i; mic->mux_idx = i;
mic->dmux_idx = -1;
if (spec->dmux_nids)
mic->dmux_idx = get_connection_index(codec,
spec->dmux_nids[0],
spec->mux_nids[0]);
} else if (spec->dmux_nids) { } else if (spec->dmux_nids) {
/* digital pin */ /* digital pin */
mic->mux_idx = 0;
i = get_connection_index(codec, spec->dmux_nids[0], pin); i = get_connection_index(codec, spec->dmux_nids[0], pin);
if (i < 0) if (i < 0)
return -1; return -1;
mic->dmux_idx = i; mic->dmux_idx = i;
mic->mux_idx = -1;
if (spec->mux_nids)
mic->mux_idx = get_connection_index(codec,
spec->mux_nids[0],
spec->dmux_nids[0]);
} }
return 0; return 0;
} }
...@@ -4557,11 +4565,11 @@ static void stac92xx_mic_detect(struct hda_codec *codec) ...@@ -4557,11 +4565,11 @@ static void stac92xx_mic_detect(struct hda_codec *codec)
mic = &spec->ext_mic; mic = &spec->ext_mic;
else else
mic = &spec->int_mic; mic = &spec->int_mic;
if (mic->dmux_idx) if (mic->dmux_idx >= 0)
snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
AC_VERB_SET_CONNECT_SEL, AC_VERB_SET_CONNECT_SEL,
mic->dmux_idx); mic->dmux_idx);
else if (mic->mux_idx >= 0)
snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0, snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0,
AC_VERB_SET_CONNECT_SEL, AC_VERB_SET_CONNECT_SEL,
mic->mux_idx); mic->mux_idx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment