+++ /dev/null
-From: Takashi Iwai <tiwai@suse.de>
-Subject: Fix / improve HP 2530p docking station support
-Patch-mainline:
-References: bnc#531437, bnc#535409
-
-Update AD codec support code to fix / improve AD1984A laptop model
-for supporting the docking station.
-
-Also sync quirk entries with the upstream, which fixes the missing
-entriy for bug #531437.
-
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-
----
- sound/pci/hda/patch_analog.c | 189 ++++++++++++++++++++++++-------------------
- 1 file changed, 108 insertions(+), 81 deletions(-)
-
---- a/sound/pci/hda/patch_analog.c
-+++ b/sound/pci/hda/patch_analog.c
-@@ -1395,8 +1395,8 @@
- {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
- /* Mic boost: 0dB */
-- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Record selector: Front mic */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-@@ -1661,10 +1661,10 @@
- SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
- SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
- /* All HP models */
-- SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
-+ SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
- SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
- /* Lenovo Thinkpad T60/X60/Z6xx */
-- SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
-+ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
- /* HP nx6320 (reversed SSID, H/W bug) */
- SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
- {}
-@@ -1873,8 +1873,8 @@
- #define AD1988_SPDIF_OUT_HDMI 0x0b
- #define AD1988_SPDIF_IN 0x07
-
--static hda_nid_t ad1989b_slave_dig_outs[2] = {
-- AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI
-+static hda_nid_t ad1989b_slave_dig_outs[] = {
-+ AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
- };
-
- static struct hda_input_mux ad1988_6stack_capture_source = {
-@@ -2276,10 +2276,6 @@
- {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
- {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
- {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-- /* ADCs; muted */
-- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- { }
- };
-@@ -2387,10 +2383,6 @@
- {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
- {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
- {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-- /* ADCs; muted */
-- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Analog Mix output amp */
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
- { }
-@@ -2462,10 +2454,6 @@
- {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
- {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
- {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-- /* ADCs; muted */
-- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Analog Mix output amp */
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
- { }
-@@ -3198,10 +3186,10 @@
- {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
- /* Port-B (front mic) pin */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Port-C (rear mic) pin */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* 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)},
-@@ -3352,7 +3340,7 @@
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* docking mic boost */
-- {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-+ {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* Analog mixer - docking mic; mute as default */
- {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* enable EAPD bit */
-@@ -3462,7 +3450,7 @@
-
- static struct snd_pci_quirk ad1984_cfg_tbl[] = {
- /* Lenovo Thinkpad T61/X61 */
-- SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
-+ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
- SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
- {}
- };
-@@ -3616,10 +3604,10 @@
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Port-B (front mic) pin */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Port-C (rear line-in) pin */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Port-E (rear mic) pin */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-@@ -3667,19 +3655,29 @@
- * Port F: Internal speakers
- */
-
--static struct hda_input_mux ad1884a_laptop_capture_source = {
-- .num_items = 4,
-- .items = {
-- { "Mic", 0x0 }, /* port-B */
-- { "Internal Mic", 0x1 }, /* port-C */
-- { "Dock Mic", 0x4 }, /* port-E */
-- { "Mix", 0x3 },
-- },
--};
-+static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-+ int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-+ int mute = (!ucontrol->value.integer.value[0] &&
-+ !ucontrol->value.integer.value[1]);
-+ /* toggle GPIO1 according to the mute state */
-+ snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-+ mute ? 0x02 : 0x0);
-+ return ret;
-+}
-
- static struct snd_kcontrol_new ad1884a_laptop_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_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
- HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-@@ -3696,36 +3694,9 @@
- HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-- {
-- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-- /* The multiple "Capture Source" controls confuse alsamixer
-- * So call somewhat different..
-- */
-- /* .name = "Capture Source", */
-- .name = "Input Source",
-- .count = 2,
-- .info = ad198x_mux_enum_info,
-- .get = ad198x_mux_enum_get,
-- .put = ad198x_mux_enum_put,
-- },
- { } /* end */
- };
-
--static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
-- struct snd_ctl_elem_value *ucontrol)
--{
-- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-- int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-- int mute = (!ucontrol->value.integer.value[0] &&
-- !ucontrol->value.integer.value[1]);
-- /* toggle GPIO1 according to the mute state */
-- snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-- mute ? 0x02 : 0x0);
-- return ret;
--}
--
- static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
- /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
-@@ -3797,6 +3768,63 @@
- return 0;
- }
-
-+/* mute internal speaker if HP or docking HP is plugged */
-+static void ad1884a_laptop_automute(struct hda_codec *codec)
-+{
-+ unsigned int present;
-+
-+ present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0);
-+ present &= AC_PINSENSE_PRESENCE;
-+ if (!present) {
-+ present = snd_hda_codec_read(codec, 0x12, 0,
-+ AC_VERB_GET_PIN_SENSE, 0);
-+ present &= AC_PINSENSE_PRESENCE;
-+ }
-+ snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-+ HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-+ snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
-+ present ? 0x00 : 0x02);
-+}
-+
-+/* switch to external mic if plugged */
-+static void ad1884a_laptop_automic(struct hda_codec *codec)
-+{
-+ unsigned int idx;
-+
-+ if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) &
-+ AC_PINSENSE_PRESENCE)
-+ idx = 0;
-+ else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) &
-+ AC_PINSENSE_PRESENCE)
-+ idx = 4;
-+ else
-+ idx = 1;
-+ snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
-+}
-+
-+/* unsolicited event for HP jack sensing */
-+static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
-+ unsigned int res)
-+{
-+ switch (res >> 26) {
-+ case AD1884A_HP_EVENT:
-+ ad1884a_laptop_automute(codec);
-+ break;
-+ case AD1884A_MIC_EVENT:
-+ ad1884a_laptop_automic(codec);
-+ break;
-+ }
-+}
-+
-+/* initialize jack-sensing, too */
-+static int ad1884a_laptop_init(struct hda_codec *codec)
-+{
-+ ad198x_init(codec);
-+ ad1884a_laptop_automute(codec);
-+ ad1884a_laptop_automic(codec);
-+ return 0;
-+}
-+
- /* additional verbs for laptop model */
- static struct hda_verb ad1884a_laptop_verbs[] = {
- /* Port-A (HP) pin - always unmuted */
-@@ -3804,18 +3832,28 @@
- /* 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},
-+ /* Port-F (int speaker) pin */
-+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-+ /* required for compaq 6530s/6531s speaker output */
-+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* Port-C pin - internal mic-in */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-+ /* Port-D (docking line-out) pin - default unmuted */
-+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* analog mix */
- {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* unsolicited event for pin-sense */
- {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-+ {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_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 */
- { } /* end */
- };
-
-@@ -3973,21 +4011,11 @@
- SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
- SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
- SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x3072, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x3073, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x3074, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x3075, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x3076, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x3077, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x3078, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x3079, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x307a, "HP", AD1884A_MOBILE),
-- SND_PCI_QUIRK(0x103c, 0x30e1, "HP 2530p", AD1884A_LAPTOP),
-- SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
-- SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
-- SND_PCI_QUIRK(0x103c, 0x360d, "HP 6530b", AD1884A_LAPTOP),
-- SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP),
-- SND_PCI_QUIRK(0x103c, 0x3632, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
-+ SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
-+ SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "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(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
- {}
- };
-@@ -4030,9 +4058,8 @@
- spec->mixers[0] = ad1884a_laptop_mixers;
- spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
- spec->multiout.dig_out_nid = 0;
-- spec->input_mux = &ad1884a_laptop_capture_source;
-- codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
-- codec->patch_ops.init = ad1884a_hp_init;
-+ codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
-+ codec->patch_ops.init = ad1884a_laptop_init;
- /* set the upper-limit for mixer amp to 0dB for avoiding the
- * possible damage by overloading
- */