Merge branch 'fix/hda' into for-linus
[pandora-kernel.git] / sound / pci / hda / patch_analog.c
index 69a941c..e9fdfc4 100644 (file)
@@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = {
 static int ad198x_build_controls(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
+       struct snd_kcontrol *kctl;
        unsigned int i;
        int err;
 
@@ -208,9 +209,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
                        if (!kctl)
                                return -ENOMEM;
                        kctl->private_value = spec->beep_amp;
-                       err = snd_hda_ctl_add(codec,
-                                               get_amp_nid_(spec->beep_amp),
-                                               kctl);
+                       err = snd_hda_ctl_add(codec, 0, kctl);
                        if (err < 0)
                                return err;
                }
@@ -239,6 +238,27 @@ static int ad198x_build_controls(struct hda_codec *codec)
        }
 
        ad198x_free_kctls(codec); /* no longer needed */
+
+       /* assign Capture Source enums to NID */
+       kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+       if (!kctl)
+               kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+       for (i = 0; kctl && i < kctl->count; i++) {
+               err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
+               if (err < 0)
+                       return err;
+       }
+
+       /* assign IEC958 enums to NID */
+       kctl = snd_hda_find_mixer_ctl(codec,
+                       SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
+       if (kctl) {
+               err = snd_hda_add_nid(codec, kctl, 0,
+                                     spec->multiout.dig_out_nid);
+               if (err < 0)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -421,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec)
        return 0;
 }
 
+static inline void ad198x_shutup(struct hda_codec *codec)
+{
+       snd_hda_shutup_pins(codec);
+}
+
 static void ad198x_free_kctls(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
@@ -434,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec)
        snd_array_free(&spec->kctls);
 }
 
+static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
+                               hda_nid_t hp)
+{
+       struct ad198x_spec *spec = codec->spec;
+       snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                           !spec->inv_eapd ? 0x00 : 0x02);
+       snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                           !spec->inv_eapd ? 0x00 : 0x02);
+}
+
+static void ad198x_power_eapd(struct hda_codec *codec)
+{
+       /* We currently only handle front, HP */
+       switch (codec->vendor_id) {
+       case 0x11d41882:
+       case 0x11d4882a:
+       case 0x11d41884:
+       case 0x11d41984:
+       case 0x11d41883:
+       case 0x11d4184a:
+       case 0x11d4194a:
+       case 0x11d4194b:
+               ad198x_power_eapd_write(codec, 0x12, 0x11);
+               break;
+       case 0x11d41981:
+       case 0x11d41983:
+               ad198x_power_eapd_write(codec, 0x05, 0x06);
+               break;
+       case 0x11d41986:
+               ad198x_power_eapd_write(codec, 0x1b, 0x1a);
+               break;
+       case 0x11d41988:
+       case 0x11d4198b:
+       case 0x11d4989a:
+       case 0x11d4989b:
+               ad198x_power_eapd_write(codec, 0x29, 0x22);
+               break;
+       }
+}
+
 static void ad198x_free(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
@@ -441,11 +506,21 @@ static void ad198x_free(struct hda_codec *codec)
        if (!spec)
                return;
 
+       ad198x_shutup(codec);
        ad198x_free_kctls(codec);
        kfree(spec);
        snd_hda_detach_beep_device(codec);
 }
 
+#ifdef SND_HDA_NEEDS_RESUME
+static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       ad198x_shutup(codec);
+       ad198x_power_eapd(codec);
+       return 0;
+}
+#endif
+
 static struct hda_codec_ops ad198x_patch_ops = {
        .build_controls = ad198x_build_controls,
        .build_pcms = ad198x_build_pcms,
@@ -454,6 +529,10 @@ static struct hda_codec_ops ad198x_patch_ops = {
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        .check_power_status = ad198x_check_power_status,
 #endif
+#ifdef SND_HDA_NEEDS_RESUME
+       .suspend = ad198x_suspend,
+#endif
+       .reboot_notify = ad198x_shutup,
 };
 
 
@@ -701,6 +780,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "External Amplifier",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
                .info = ad198x_eapd_info,
                .get = ad198x_eapd_get,
                .put = ad198x_eapd_put,
@@ -808,6 +888,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = ad1986a_hp_master_sw_put,
@@ -1008,7 +1089,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
        SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
        SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
+       SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
        SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
@@ -1612,6 +1693,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = {
        HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
                .name = "Master Playback Switch",
                .info = ad198x_eapd_info,
                .get = ad198x_eapd_get,
@@ -1805,6 +1887,14 @@ static int patch_ad1981(struct hda_codec *codec)
        case AD1981_THINKPAD:
                spec->mixers[0] = ad1981_thinkpad_mixers;
                spec->input_mux = &ad1981_thinkpad_capture_source;
+               /* set the upper-limit for mixer amp to 0dB for avoiding the
+                * possible damage by overloading
+                */
+               snd_hda_override_amp_caps(codec, 0x11, 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;
        case AD1981_TOSHIBA:
                spec->mixers[0] = ad1981_hp_mixers;
@@ -2136,6 +2226,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "External Amplifier",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
                .info = ad198x_eapd_info,
                .get = ad198x_eapd_get,
                .put = ad198x_eapd_put,
@@ -2257,6 +2348,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "IEC958 Playback Source",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
                .info = ad1988_spdif_playback_source_info,
                .get = ad1988_spdif_playback_source_get,
                .put = ad1988_spdif_playback_source_put,
@@ -2372,6 +2464,12 @@ static struct hda_verb ad1988_spdif_init_verbs[] = {
        { }
 };
 
+static struct hda_verb ad1988_spdif_in_init_verbs[] = {
+       /* unmute SPDIF input pin */
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       { }
+};
+
 /* AD1989 has no ADC -> SPDIF route */
 static struct hda_verb ad1989_spdif_init_verbs[] = {
        /* SPDIF-1 out pin */
@@ -2589,7 +2687,7 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
        if (! knew->name)
                return -ENOMEM;
        if (get_amp_nid_(val))
-               knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
        knew->private_value = val;
        return 0;
 }
@@ -3107,8 +3205,11 @@ static int patch_ad1988(struct hda_codec *codec)
                                ad1988_spdif_init_verbs;
                }
        }
-       if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a)
+       if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
                spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
+               spec->init_verbs[spec->num_init_verbs++] =
+                       ad1988_spdif_in_init_verbs;
+       }
 
        codec->patch_ops = ad198x_patch_ops;
        switch (board_config) {
@@ -3747,6 +3848,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = ad1884a_mobile_master_sw_put,
@@ -3775,6 +3877,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,
                .put = ad1884a_mobile_master_sw_put,
@@ -4116,6 +4219,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
 /*     HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
                .name = "Master Playback Switch",
                .info = snd_hda_mixer_amp_switch_info,
                .get = snd_hda_mixer_amp_switch_get,