]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - sound/pci/hda/patch_realtek.c
ALSA: hda/realtek - Add default procedure for suspend and resume state
[mirror_ubuntu-bionic-kernel.git] / sound / pci / hda / patch_realtek.c
index 58df440013c54c00da464166f1905bfd4edfbd36..c4a1b496d7bb101699e68e92c8fe25455df45b00 100644 (file)
@@ -2324,10 +2324,11 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
 
        SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
-       SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
        SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
+       SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
+       SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
        SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
@@ -2342,6 +2343,7 @@ static const struct hda_model_fixup alc882_fixup_models[] = {
        {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
        {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
        {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
+       {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
        {}
 };
 
@@ -2573,18 +2575,37 @@ static int patch_alc262(struct hda_codec *codec)
  *  ALC268
  */
 /* bind Beep switches of both NID 0x0f and 0x10 */
-static const struct hda_bind_ctls alc268_bind_beep_sw = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
-               0
-       },
-};
+static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned long pval;
+       int err;
+
+       mutex_lock(&codec->control_mutex);
+       pval = kcontrol->private_value;
+       kcontrol->private_value = (pval & ~0xff) | 0x0f;
+       err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       if (err >= 0) {
+               kcontrol->private_value = (pval & ~0xff) | 0x10;
+               err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       }
+       kcontrol->private_value = pval;
+       mutex_unlock(&codec->control_mutex);
+       return err;
+}
 
 static const struct snd_kcontrol_new alc268_beep_mixer[] = {
        HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
-       HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Beep Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = alc268_beep_switch_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
+       },
        { }
 };
 
@@ -3041,6 +3062,135 @@ static void alc283_shutup(struct hda_codec *codec)
        alc_write_coef_idx(codec, 0x43, 0x9614);
 }
 
+static void alc256_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+       bool hp_pin_sense;
+
+       if (!hp_pin)
+               return;
+
+       msleep(30);
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       if (hp_pin_sense)
+               msleep(2);
+
+       alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(85);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+       if (hp_pin_sense)
+               msleep(100);
+
+       alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
+       alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
+}
+
+static void alc256_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+       bool hp_pin_sense;
+
+       if (!hp_pin) {
+               alc269_shutup(codec);
+               return;
+       }
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       if (hp_pin_sense)
+               msleep(2);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(85);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+       alc_update_coef_idx(codec, 0x46, 0, 3 << 12); /* 3k pull low control for Headset jack. */
+
+       if (hp_pin_sense)
+               msleep(100);
+
+       alc_auto_setup_eapd(codec, false);
+       snd_hda_shutup_pins(codec);
+}
+
+static void alc_default_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+       bool hp_pin_sense;
+
+       if (!hp_pin)
+               return;
+
+       msleep(30);
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       if (hp_pin_sense)
+               msleep(2);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(85);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+       if (hp_pin_sense)
+               msleep(100);
+}
+
+static void alc_default_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+       bool hp_pin_sense;
+
+       if (!hp_pin) {
+               alc269_shutup(codec);
+               return;
+       }
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       if (hp_pin_sense)
+               msleep(2);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(85);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+       if (hp_pin_sense)
+               msleep(100);
+
+       alc_auto_setup_eapd(codec, false);
+       snd_hda_shutup_pins(codec);
+}
+
 static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
                             unsigned int val)
 {
@@ -3752,6 +3902,16 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
                UPDATE_COEF(0x4a, 3<<10, 0),
                {}
        };
+       static struct coef_fw coef0274[] = {
+               UPDATE_COEF(0x4a, 0x0100, 0),
+               UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
+               UPDATE_COEF(0x6b, 0xf000, 0x5000),
+               UPDATE_COEF(0x4a, 0x0010, 0),
+               UPDATE_COEF(0x4a, 0x0c00, 0x0c00),
+               WRITE_COEF(0x45, 0x5289),
+               UPDATE_COEF(0x4a, 0x0c00, 0),
+               {}
+       };
 
        switch (codec->core.vendor_id) {
        case 0x10ec0255:
@@ -3762,6 +3922,11 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
                alc_process_coef_fw(codec, coef0256);
                alc_process_coef_fw(codec, coef0255);
                break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_process_coef_fw(codec, coef0274);
+               break;
        case 0x10ec0233:
        case 0x10ec0283:
                alc_process_coef_fw(codec, coef0233);
@@ -3839,7 +4004,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                UPDATE_COEF(0x63, 3<<14, 0),
                {}
        };
-
+       static struct coef_fw coef0274[] = {
+               UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
+               UPDATE_COEF(0x4a, 0x0010, 0),
+               UPDATE_COEF(0x6b, 0xf000, 0),
+               {}
+       };
 
        switch (codec->core.vendor_id) {
        case 0x10ec0255:
@@ -3849,6 +4019,14 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                alc_process_coef_fw(codec, coef0255);
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
                break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_write_coef_idx(codec, 0x45, 0x4689);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0274);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
        case 0x10ec0233:
        case 0x10ec0283:
                alc_write_coef_idx(codec, 0x45, 0xc429);
@@ -3946,6 +4124,13 @@ static void alc_headset_mode_default(struct hda_codec *codec)
                WRITE_COEF(0xb7, 0x802b),
                {}
        };
+       static struct coef_fw coef0274[] = {
+               WRITE_COEF(0x45, 0x4289),
+               UPDATE_COEF(0x4a, 0x0010, 0x0010),
+               UPDATE_COEF(0x6b, 0x0f00, 0),
+               UPDATE_COEF(0x49, 0x0300, 0x0300),
+               {}
+       };
 
        switch (codec->core.vendor_id) {
        case 0x10ec0225:
@@ -3957,6 +4142,11 @@ static void alc_headset_mode_default(struct hda_codec *codec)
        case 0x10ec0256:
                alc_process_coef_fw(codec, coef0255);
                break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_process_coef_fw(codec, coef0274);
+               break;
        case 0x10ec0233:
        case 0x10ec0283:
                alc_process_coef_fw(codec, coef0233);
@@ -4042,6 +4232,11 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
        case 0x10ec0256:
                alc_process_coef_fw(codec, coef0256);
                break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_write_coef_idx(codec, 0x45, 0xd689);
+               break;
        case 0x10ec0233:
        case 0x10ec0283:
                alc_process_coef_fw(codec, coef0233);
@@ -4136,6 +4331,11 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
        case 0x10ec0256:
                alc_process_coef_fw(codec, coef0256);
                break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_write_coef_idx(codec, 0x45, 0xe689);
+               break;
        case 0x10ec0233:
        case 0x10ec0283:
                alc_process_coef_fw(codec, coef0233);
@@ -4199,6 +4399,13 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                UPDATE_COEF(0x49, 1<<8, 1<<8),
                {}
        };
+       static struct coef_fw coef0274[] = {
+               UPDATE_COEF(0x4a, 0x0010, 0),
+               UPDATE_COEF(0x4a, 0x8000, 0),
+               WRITE_COEF(0x45, 0xd289),
+               UPDATE_COEF(0x49, 0x0300, 0x0300),
+               {}
+       };
 
        switch (codec->core.vendor_id) {
        case 0x10ec0255:
@@ -4208,6 +4415,14 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                val = alc_read_coef_idx(codec, 0x46);
                is_ctia = (val & 0x0070) == 0x0070;
                break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_process_coef_fw(codec, coef0274);
+               msleep(80);
+               val = alc_read_coef_idx(codec, 0x46);
+               is_ctia = (val & 0x00f0) == 0x00f0;
+               break;
        case 0x10ec0233:
        case 0x10ec0283:
                alc_write_coef_idx(codec, 0x45, 0xd029);
@@ -5852,7 +6067,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
+       SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC),
@@ -5860,13 +6079,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+       SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
@@ -6014,6 +6230,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
        {.id = ALC292_FIXUP_TPT440, .name = "tpt440"},
        {.id = ALC292_FIXUP_TPT460, .name = "tpt460"},
+       {.id = ALC233_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
        {}
 };
 #define ALC225_STANDARD_PINS \
@@ -6380,7 +6597,8 @@ static int patch_alc269(struct hda_codec *codec)
        codec->patch_ops.suspend = alc269_suspend;
        codec->patch_ops.resume = alc269_resume;
 #endif
-       spec->shutup = alc269_shutup;
+       spec->shutup = alc_default_shutup;
+       spec->init_hook = alc_default_init;
 
        snd_hda_pick_fixup(codec, alc269_fixup_models,
                       alc269_fixup_tbl, alc269_fixups);
@@ -6420,6 +6638,7 @@ static int patch_alc269(struct hda_codec *codec)
                }
                if (err < 0)
                        goto error;
+               spec->shutup = alc269_shutup;
                spec->init_hook = alc269_fill_coef;
                alc269_fill_coef(codec);
                break;
@@ -6460,18 +6679,24 @@ static int patch_alc269(struct hda_codec *codec)
                break;
        case 0x10ec0256:
                spec->codec_variant = ALC269_TYPE_ALC256;
+               spec->shutup = alc256_shutup;
+               spec->init_hook = alc256_init;
                spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
                alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
                break;
        case 0x10ec0225:
        case 0x10ec0295:
+               spec->codec_variant = ALC269_TYPE_ALC225;
+               break;
        case 0x10ec0299:
                spec->codec_variant = ALC269_TYPE_ALC225;
+               spec->gen.mixer_nid = 0; /* no loopback on ALC299 */
                break;
        case 0x10ec0234:
        case 0x10ec0274:
        case 0x10ec0294:
                spec->codec_variant = ALC269_TYPE_ALC294;
+               alc_update_coef_idx(codec, 0x6b, 0x0018, (1<<4) | (1<<3)); /* UAJ MIC Vref control by verb */
                break;
        case 0x10ec0700:
        case 0x10ec0701:
@@ -7338,6 +7563,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
        {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
        {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
        {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
+       {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
        {}
 };