Merge branch 'topic/misc' into for-linus
[sfrench/cifs-2.6.git] / sound / pci / hda / patch_realtek.c
index c5208c90784beadae8af2c6d64341888d22d4d18..f1a03f223495f70043914326c4a563798f10ef34 100644 (file)
@@ -282,12 +282,6 @@ struct alc_mic_route {
        unsigned char amix_idx;
 };
 
-struct alc_jack {
-       hda_nid_t nid;
-       int type;
-       struct snd_jack *jack;
-};
-
 #define MUX_IDX_UNDEF  ((unsigned char)-1)
 
 struct alc_customize_define {
@@ -366,9 +360,6 @@ struct alc_spec {
        /* PCM information */
        struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
 
-       /* jack detection */
-       struct snd_array jacks;
-
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
        struct alc_customize_define cdefine;
@@ -394,6 +385,7 @@ struct alc_spec {
        /* other flags */
        unsigned int no_analog :1; /* digital I/O only */
        unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
+       unsigned int single_input_src:1;
        int init_amp;
        int codec_variant;      /* flag for other variants */
 
@@ -1032,94 +1024,32 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
        alc_fix_pll(codec);
 }
 
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-static void alc_free_jack_priv(struct snd_jack *jack)
-{
-       struct alc_jack *jacks = jack->private_data;
-       jacks->nid = 0;
-       jacks->jack = NULL;
-}
-
-static int alc_add_jack(struct hda_codec *codec,
-               hda_nid_t nid, int type)
-{
-       struct alc_spec *spec;
-       struct alc_jack *jack;
-       const char *name;
-       int err;
-
-       spec = codec->spec;
-       snd_array_init(&spec->jacks, sizeof(*jack), 32);
-       jack = snd_array_new(&spec->jacks);
-       if (!jack)
-               return -ENOMEM;
-
-       jack->nid = nid;
-       jack->type = type;
-       name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
-
-       err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
-       if (err < 0)
-               return err;
-       jack->jack->private_data = jack;
-       jack->jack->private_free = alc_free_jack_priv;
-       return 0;
-}
-
-static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct alc_spec *spec = codec->spec;
-       struct alc_jack *jacks = spec->jacks.list;
-
-       if (jacks) {
-               int i;
-               for (i = 0; i < spec->jacks.used; i++) {
-                       if (jacks->nid == nid) {
-                               unsigned int present;
-                               present = snd_hda_jack_detect(codec, nid);
-
-                               present = (present) ? jacks->type : 0;
-
-                               snd_jack_report(jacks->jack, present);
-                       }
-                       jacks++;
-               }
-       }
-}
-
 static int alc_init_jacks(struct hda_codec *codec)
 {
+#ifdef CONFIG_SND_HDA_INPUT_JACK
        struct alc_spec *spec = codec->spec;
        int err;
        unsigned int hp_nid = spec->autocfg.hp_pins[0];
        unsigned int mic_nid = spec->ext_mic.pin;
 
        if (hp_nid) {
-               err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
+               err = snd_hda_input_jack_add(codec, hp_nid,
+                                            SND_JACK_HEADPHONE, NULL);
                if (err < 0)
                        return err;
-               alc_report_jack(codec, hp_nid);
+               snd_hda_input_jack_report(codec, hp_nid);
        }
 
        if (mic_nid) {
-               err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
+               err = snd_hda_input_jack_add(codec, mic_nid,
+                                            SND_JACK_MICROPHONE, NULL);
                if (err < 0)
                        return err;
-               alc_report_jack(codec, mic_nid);
+               snd_hda_input_jack_report(codec, mic_nid);
        }
-
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
        return 0;
 }
-#else
-static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
-}
-
-static inline int alc_init_jacks(struct hda_codec *codec)
-{
-       return 0;
-}
-#endif
 
 static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
 {
@@ -1133,11 +1063,8 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
                nid = spec->autocfg.hp_pins[i];
                if (!nid)
                        break;
-               if (snd_hda_jack_detect(codec, nid)) {
-                       spec->jack_present = 1;
-                       break;
-               }
-               alc_report_jack(codec, spec->autocfg.hp_pins[i]);
+               snd_hda_input_jack_report(codec, nid);
+               spec->jack_present |= snd_hda_jack_detect(codec, nid);
        }
 
        mute = spec->jack_present ? HDA_AMP_MUTE : 0;
@@ -1243,7 +1170,7 @@ static void alc_mic_automute(struct hda_codec *codec)
                                          AC_VERB_SET_CONNECT_SEL,
                                          alive->mux_idx);
        }
-       alc_report_jack(codec, spec->ext_mic.pin);
+       snd_hda_input_jack_report(codec, spec->ext_mic.pin);
 
        /* FIXME: analog mixer */
 }
@@ -2295,13 +2222,13 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0f, 2, 0x0,
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
                HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0f, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
@@ -2312,7 +2239,6 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
        { } /* end */
 };
 
-
 static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -3922,6 +3848,8 @@ static struct hda_amp_list alc880_lg_loopbacks[] = {
  * Common callbacks
  */
 
+static void alc_init_special_input_src(struct hda_codec *codec);
+
 static int alc_init(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -3932,6 +3860,7 @@ static int alc_init(struct hda_codec *codec)
 
        for (i = 0; i < spec->num_init_verbs; i++)
                snd_hda_sequence_write(codec, spec->init_verbs[i]);
+       alc_init_special_input_src(codec);
 
        if (spec->init_hook)
                spec->init_hook(codec);
@@ -4287,6 +4216,7 @@ static void alc_free(struct hda_codec *codec)
                return;
 
        alc_shutup(codec);
+       snd_hda_input_jack_free(codec);
        alc_free_kctls(codec);
        kfree(spec);
        snd_hda_detach_beep_device(codec);
@@ -5154,7 +5084,9 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
 
        switch (cfg->line_out_type) {
        case AUTO_PIN_SPEAKER_OUT:
-               return "Speaker";
+               if (cfg->line_outs == 1)
+                       return "Speaker";
+               break;
        case AUTO_PIN_HP_OUT:
                return "Headphone";
        default:
@@ -5208,16 +5140,19 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                                return err;
                } else {
                        const char *name = pfx;
-                       if (!name)
+                       int index = i;
+                       if (!name) {
                                name = chname[i];
+                               index = 0;
+                       }
                        err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                               name, i,
+                                               name, index,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                              name, i,
+                                              name, index,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -5588,6 +5523,7 @@ static void fixup_single_adc(struct hda_codec *codec)
                        spec->capsrc_nids += i;
                spec->adc_nids += i;
                spec->num_adc_nids = 1;
+               spec->single_input_src = 1;
        }
 }
 
@@ -5599,6 +5535,16 @@ static void fixup_dual_adc_switch(struct hda_codec *codec)
        init_capsrc_for_pin(codec, spec->int_mic.pin);
 }
 
+/* initialize some special cases for input sources */
+static void alc_init_special_input_src(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       if (spec->dual_adc_switch)
+               fixup_dual_adc_switch(codec);
+       else if (spec->single_input_src)
+               init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin);
+}
+
 static void set_capture_mixer(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -5614,7 +5560,7 @@ static void set_capture_mixer(struct hda_codec *codec)
                int mux = 0;
                int num_adcs = spec->num_adc_nids;
                if (spec->dual_adc_switch)
-                       fixup_dual_adc_switch(codec);
+                       num_adcs = 1;
                else if (spec->auto_mic)
                        fixup_automic_adc(codec);
                else if (spec->input_mux) {
@@ -5623,8 +5569,6 @@ static void set_capture_mixer(struct hda_codec *codec)
                        else if (spec->input_mux->num_items == 1)
                                fixup_single_adc(codec);
                }
-               if (spec->dual_adc_switch)
-                       num_adcs = 1;
                spec->cap_mixer = caps[mux][num_adcs - 1];
        }
 }
@@ -10751,6 +10695,7 @@ static struct alc_config_preset alc882_presets[] = {
  */
 enum {
        PINFIX_ABIT_AW9D_MAX,
+       PINFIX_LENOVO_Y530,
        PINFIX_PB_M5210,
        PINFIX_ACER_ASPIRE_7736,
 };
@@ -10765,6 +10710,14 @@ static const struct alc_fixup alc882_fixups[] = {
                        { }
                }
        },
+       [PINFIX_LENOVO_Y530] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x15, 0x99130112 }, /* rear int speakers */
+                       { 0x16, 0x99130111 }, /* subwoofer */
+                       { }
+               }
+       },
        [PINFIX_PB_M5210] = {
                .type = ALC_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
@@ -10780,6 +10733,7 @@ static const struct alc_fixup alc882_fixups[] = {
 
 static struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
+       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
        SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
        {}
@@ -10832,23 +10786,28 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
        hda_nid_t pin, dac;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
-               pin = spec->autocfg.hp_pins[i];
-               if (!pin)
-                       break;
-               dac = spec->multiout.hp_nid;
-               if (!dac)
-                       dac = spec->multiout.dac_nids[0]; /* to front */
-               alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
+       if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) {
+               for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+                       pin = spec->autocfg.hp_pins[i];
+                       if (!pin)
+                               break;
+                       dac = spec->multiout.hp_nid;
+                       if (!dac)
+                               dac = spec->multiout.dac_nids[0]; /* to front */
+                       alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
+               }
        }
-       for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
-               pin = spec->autocfg.speaker_pins[i];
-               if (!pin)
-                       break;
-               dac = spec->multiout.extra_out_nid[0];
-               if (!dac)
-                       dac = spec->multiout.dac_nids[0]; /* to front */
-               alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
+
+       if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
+                       pin = spec->autocfg.speaker_pins[i];
+                       if (!pin)
+                               break;
+                       dac = spec->multiout.extra_out_nid[0];
+                       if (!dac)
+                               dac = spec->multiout.dac_nids[0]; /* to front */
+                       alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
+               }
        }
 }
 
@@ -13799,6 +13758,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
 }
 
 #define alc268_auto_init_analog_input  alc882_auto_init_analog_input
+#define alc268_auto_init_input_src     alc882_auto_init_input_src
 
 /* init callback for auto-configuration model -- overriding the default init */
 static void alc268_auto_init(struct hda_codec *codec)
@@ -13808,6 +13768,7 @@ static void alc268_auto_init(struct hda_codec *codec)
        alc268_auto_init_hp_out(codec);
        alc268_auto_init_mono_speaker_out(codec);
        alc268_auto_init_analog_input(codec);
+       alc268_auto_init_input_src(codec);
        alc_auto_init_digital(codec);
        if (spec->unsol_event)
                alc_inithook(codec);
@@ -14095,7 +14056,6 @@ static int patch_alc268(struct hda_codec *codec)
        if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, 0x07);
-               int i;
 
                spec->capsrc_nids = alc268_capsrc_nids;
                /* get type */
@@ -14115,13 +14075,6 @@ static int patch_alc268(struct hda_codec *codec)
                        spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
                        add_mixer(spec, alc268_capture_mixer);
                }
-               /* set default input source */
-               for (i = 0; i < spec->num_adc_nids; i++)
-                       snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
-                               0, AC_VERB_SET_CONNECT_SEL,
-                               i < spec->num_mux_defs ?
-                               spec->input_mux[i].items[0].index :
-                               spec->input_mux->items[0].index);
        }
 
        spec->vmaster_nid = 0x02;
@@ -14498,7 +14451,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
                                 HDA_AMP_MUTE, bits);
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
                                 HDA_AMP_MUTE, bits);
-       alc_report_jack(codec, nid);
+       snd_hda_input_jack_report(codec, nid);
 }
 
 /* unsolicited event for HP jack sensing */
@@ -14810,11 +14763,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
                fillup_priv_adc_nids(codec, alc269_adc_candidates,
                                     sizeof(alc269_adc_candidates));
 
-       /* set default input source */
-       if (!spec->dual_adc_switch)
-               select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
-                                       spec->input_mux->items[0].index);
-
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
                return err;
@@ -14828,6 +14776,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
 #define alc269_auto_init_multi_out     alc268_auto_init_multi_out
 #define alc269_auto_init_hp_out                alc268_auto_init_hp_out
 #define alc269_auto_init_analog_input  alc882_auto_init_analog_input
+#define alc269_auto_init_input_src     alc882_auto_init_input_src
 
 
 /* init callback for auto-configuration model -- overriding the default init */
@@ -14837,6 +14786,8 @@ static void alc269_auto_init(struct hda_codec *codec)
        alc269_auto_init_multi_out(codec);
        alc269_auto_init_hp_out(codec);
        alc269_auto_init_analog_input(codec);
+       if (!spec->dual_adc_switch)
+               alc269_auto_init_input_src(codec);
        alc_auto_init_digital(codec);
        if (spec->unsol_event)
                alc_inithook(codec);
@@ -15015,7 +14966,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
        SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),