ALSA: hda/realtek - New codec support for ALC298
[linux-2.6-block.git] / sound / pci / hda / patch_realtek.c
index 172395465e8a63963d096ec29f3ee04f7bfe5948..65f1f4e18ea5c5885d4a0e9daedf189c92c7fe3f 100644 (file)
@@ -96,6 +96,8 @@ struct alc_spec {
        hda_nid_t cap_mute_led_nid;
 
        unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */
+       unsigned int gpio_mute_led_mask;
+       unsigned int gpio_mic_led_mask;
 
        hda_nid_t headset_mic_pin;
        hda_nid_t headphone_mic_pin;
@@ -319,10 +321,12 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
                break;
        case 0x10ec0233:
        case 0x10ec0255:
+       case 0x10ec0256:
        case 0x10ec0282:
        case 0x10ec0283:
        case 0x10ec0286:
        case 0x10ec0288:
+       case 0x10ec0298:
                alc_update_coef_idx(codec, 0x10, 1<<9, 0);
                break;
        case 0x10ec0285:
@@ -2657,7 +2661,9 @@ enum {
        ALC269_TYPE_ALC284,
        ALC269_TYPE_ALC285,
        ALC269_TYPE_ALC286,
+       ALC269_TYPE_ALC298,
        ALC269_TYPE_ALC255,
+       ALC269_TYPE_ALC256,
 };
 
 /*
@@ -2684,7 +2690,9 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        case ALC269_TYPE_ALC282:
        case ALC269_TYPE_ALC283:
        case ALC269_TYPE_ALC286:
+       case ALC269_TYPE_ALC298:
        case ALC269_TYPE_ALC255:
+       case ALC269_TYPE_ALC256:
                ssids = alc269_ssids;
                break;
        default:
@@ -3310,41 +3318,45 @@ static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
        }
 }
 
-/* turn on/off mute LED per vmaster hook */
-static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled)
+/* update LED status via GPIO */
+static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+                               bool enabled)
 {
-       struct hda_codec *codec = private_data;
        struct alc_spec *spec = codec->spec;
        unsigned int oldval = spec->gpio_led;
 
+       if (spec->mute_led_polarity)
+               enabled = !enabled;
+
        if (enabled)
-               spec->gpio_led &= ~0x08;
+               spec->gpio_led &= ~mask;
        else
-               spec->gpio_led |= 0x08;
+               spec->gpio_led |= mask;
        if (spec->gpio_led != oldval)
                snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
                                    spec->gpio_led);
 }
 
-/* turn on/off mic-mute LED per capture hook */
-static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec,
-                                              struct snd_kcontrol *kcontrol,
-                                              struct snd_ctl_elem_value *ucontrol)
+/* turn on/off mute LED via GPIO per vmaster hook */
+static void alc_fixup_gpio_mute_hook(void *private_data, int enabled)
 {
+       struct hda_codec *codec = private_data;
        struct alc_spec *spec = codec->spec;
-       unsigned int oldval = spec->gpio_led;
 
-       if (!ucontrol)
-               return;
+       alc_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled);
+}
 
-       if (ucontrol->value.integer.value[0] ||
-           ucontrol->value.integer.value[1])
-               spec->gpio_led &= ~0x10;
-       else
-               spec->gpio_led |= 0x10;
-       if (spec->gpio_led != oldval)
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                                   spec->gpio_led);
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static void alc_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
+                                        struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (ucontrol)
+               alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
+                                   ucontrol->value.integer.value[0] ||
+                                   ucontrol->value.integer.value[1]);
 }
 
 static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
@@ -3358,9 +3370,33 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
        };
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
-               spec->gen.cap_sync_hook = alc269_fixup_hp_gpio_mic_mute_hook;
+               spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+               spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
                spec->gpio_led = 0;
+               spec->mute_led_polarity = 0;
+               spec->gpio_mute_led_mask = 0x08;
+               spec->gpio_mic_led_mask = 0x10;
+               snd_hda_add_verbs(codec, gpio_init);
+       }
+}
+
+static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_verb gpio_init[] = {
+               { 0x01, AC_VERB_SET_GPIO_MASK, 0x22 },
+               { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x22 },
+               {}
+       };
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+               spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
+               spec->gpio_led = 0;
+               spec->mute_led_polarity = 0;
+               spec->gpio_mute_led_mask = 0x02;
+               spec->gpio_mic_led_mask = 0x20;
                snd_hda_add_verbs(codec, gpio_init);
        }
 }
@@ -3402,9 +3438,11 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
        };
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
+               spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
                spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
                spec->gpio_led = 0;
+               spec->mute_led_polarity = 0;
+               spec->gpio_mute_led_mask = 0x08;
                spec->cap_mute_led_nid = 0x18;
                snd_hda_add_verbs(codec, gpio_init);
                codec->power_filter = led_power_filter;
@@ -3423,9 +3461,11 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
        };
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
+               spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
                spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
                spec->gpio_led = 0;
+               spec->mute_led_polarity = 0;
+               spec->gpio_mute_led_mask = 0x08;
                spec->cap_mute_led_nid = 0x18;
                snd_hda_add_verbs(codec, gpio_init);
                codec->power_filter = led_power_filter;
@@ -4300,6 +4340,7 @@ enum {
        ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
        ALC282_FIXUP_ASPIRE_V5_PINS,
        ALC280_FIXUP_HP_GPIO4,
+       ALC286_FIXUP_HP_GPIO_LED,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -4520,6 +4561,8 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC269_FIXUP_HEADSET_MODE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
        },
        [ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
                .type = HDA_FIXUP_FUNC,
@@ -4709,6 +4752,8 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC255_FIXUP_HEADSET_MODE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_alc255,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
        },
        [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
                .type = HDA_FIXUP_FUNC,
@@ -4744,8 +4789,6 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_dell_wmi,
-               .chained_before = true,
-               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
        },
        [ALC282_FIXUP_ASPIRE_V5_PINS] = {
                .type = HDA_FIXUP_PINS,
@@ -4767,6 +4810,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc280_fixup_hp_gpio4,
        },
+       [ALC286_FIXUP_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc286_fixup_hp_gpio_led,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -4783,13 +4830,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
        SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
-       SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
        SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -4807,6 +4855,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -4818,7 +4867,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
@@ -4886,6 +4934,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
        SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
@@ -5375,9 +5424,15 @@ static int patch_alc269(struct hda_codec *codec)
                spec->codec_variant = ALC269_TYPE_ALC286;
                spec->shutup = alc286_shutup;
                break;
+       case 0x10ec0298:
+               spec->codec_variant = ALC269_TYPE_ALC298;
+               break;
        case 0x10ec0255:
                spec->codec_variant = ALC269_TYPE_ALC255;
                break;
+       case 0x10ec0256:
+               spec->codec_variant = ALC269_TYPE_ALC256;
+               break;
        }
 
        if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) {
@@ -5696,22 +5751,6 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec,
        }
 }
 
-/* turn on/off mute LED per vmaster hook */
-static void alc662_led_gpio1_mute_hook(void *private_data, int enabled)
-{
-       struct hda_codec *codec = private_data;
-       struct alc_spec *spec = codec->spec;
-       unsigned int oldval = spec->gpio_led;
-
-       if (enabled)
-               spec->gpio_led |= 0x01;
-       else
-               spec->gpio_led &= ~0x01;
-       if (spec->gpio_led != oldval)
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                                   spec->gpio_led);
-}
-
 /* avoid D3 for keeping GPIO up */
 static unsigned int gpio_led_power_filter(struct hda_codec *codec,
                                          hda_nid_t nid,
@@ -5734,8 +5773,10 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec,
        };
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gen.vmaster_mute.hook = alc662_led_gpio1_mute_hook;
+               spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
                spec->gpio_led = 0;
+               spec->mute_led_polarity = 1;
+               spec->gpio_mute_led_mask = 0x01;
                snd_hda_add_verbs(codec, gpio_init);
                codec->power_filter = gpio_led_power_filter;
        }
@@ -6313,6 +6354,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0233, .name = "ALC233", .patch = patch_alc269 },
        { .id = 0x10ec0235, .name = "ALC233", .patch = patch_alc269 },
        { .id = 0x10ec0255, .name = "ALC255", .patch = patch_alc269 },
+       { .id = 0x10ec0256, .name = "ALC256", .patch = patch_alc269 },
        { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
        { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
        { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
@@ -6332,6 +6374,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
        { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 },
        { .id = 0x10ec0293, .name = "ALC293", .patch = patch_alc269 },
+       { .id = 0x10ec0298, .name = "ALC298", .patch = patch_alc269 },
        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
          .patch = patch_alc861 },
        { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },