ALSA: hda - Add debug prints for Realtek auto-init
[pandora-kernel.git] / sound / pci / hda / patch_realtek.c
index 3696ff3..ee92c73 100644 (file)
@@ -770,7 +770,7 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
 
        if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
                unsigned int pincap;
-               pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+               pincap = snd_hda_query_pin_caps(codec, nid);
                pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
                if (pincap & AC_PINCAP_VREF_80)
                        val = PIN_VREF80;
@@ -982,7 +982,7 @@ static void alc888_coef_init(struct hda_codec *codec)
        snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
        tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
        snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
-       if ((tmp & 0xf0) == 2)
+       if ((tmp & 0xf0) == 0x20)
                /* alc888S-VC */
                snd_hda_codec_read(codec, 0x20, 0,
                                   AC_VERB_SET_PROC_COEF, 0x830);
@@ -1022,6 +1022,9 @@ static void alc_subsystem_id(struct hda_codec *codec,
        if (codec->vendor_id == 0x10ec0260)
                nid = 0x17;
        ass = snd_hda_codec_get_pincfg(codec, nid);
+       snd_printd("realtek: No valid SSID, "
+                  "checking pincfg 0x%08x for NID 0x%x\n",
+                  nid, ass);
        if (!(ass & 1) && !(ass & 0x100000))
                return;
        if ((ass >> 30) != 1)   /* no physical connection */
@@ -1036,6 +1039,8 @@ static void alc_subsystem_id(struct hda_codec *codec,
        if (((ass >> 16) & 0xf) != tmp)
                return;
 do_sku:
+       snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+                  ass & 0xffff, codec->vendor_id);
        /*
         * 0 : override
         * 1 :  Swap Jack
@@ -1595,8 +1600,7 @@ static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
                                     snd_hda_mixer_amp_switch_put);
 }
 
-#define DEFINE_CAPMIX(num) \
-static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+#define _DEFINE_CAPMIX(num) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
                .name = "Capture Switch", \
@@ -1617,7 +1621,9 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
                .get = alc_cap_vol_get, \
                .put = alc_cap_vol_put, \
                .tlv = { .c = alc_cap_vol_tlv }, \
-       }, \
+       }
+
+#define _DEFINE_CAPSRC(num) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
                /* .name = "Capture Source", */ \
@@ -1626,15 +1632,28 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
                .info = alc_mux_enum_info, \
                .get = alc_mux_enum_get, \
                .put = alc_mux_enum_put, \
-       }, \
-       { } /* end */ \
+       }
+
+#define DEFINE_CAPMIX(num) \
+static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+       _DEFINE_CAPMIX(num),                                  \
+       _DEFINE_CAPSRC(num),                                  \
+       { } /* end */                                         \
+}
+
+#define DEFINE_CAPMIX_NOSRC(num) \
+static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
+       _DEFINE_CAPMIX(num),                                        \
+       { } /* end */                                               \
 }
 
 /* up to three ADCs */
 DEFINE_CAPMIX(1);
 DEFINE_CAPMIX(2);
 DEFINE_CAPMIX(3);
-
+DEFINE_CAPMIX_NOSRC(1);
+DEFINE_CAPMIX_NOSRC(2);
+DEFINE_CAPMIX_NOSRC(3);
 
 /*
  * ALC880 5-stack model
@@ -4207,7 +4226,8 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec)
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (alc880_is_input_pin(nid)) {
                        alc_set_input_pin(codec, nid, i);
-                       if (nid != ALC880_PIN_CD_NID)
+                       if (nid != ALC880_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -4297,13 +4317,22 @@ static void alc880_auto_init(struct hda_codec *codec)
 
 static void set_capture_mixer(struct alc_spec *spec)
 {
-       static struct snd_kcontrol_new *caps[3] = {
-               alc_capture_mixer1,
-               alc_capture_mixer2,
-               alc_capture_mixer3,
+       static struct snd_kcontrol_new *caps[2][3] = {
+               { alc_capture_mixer_nosrc1,
+                 alc_capture_mixer_nosrc2,
+                 alc_capture_mixer_nosrc3 },
+               { alc_capture_mixer1,
+                 alc_capture_mixer2,
+                 alc_capture_mixer3 },
        };
-       if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3)
-               spec->cap_mixer = caps[spec->num_adc_nids - 1];
+       if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
+               int mux;
+               if (spec->input_mux && spec->input_mux->num_items > 1)
+                       mux = 1;
+               else
+                       mux = 0;
+               spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
+       }
 }
 
 #define set_beep_amp(spec, nid, idx, dir) \
@@ -5673,7 +5702,8 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec)
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (nid >= 0x12) {
                        alc_set_input_pin(codec, nid, i);
-                       if (nid != ALC260_PIN_CD_NID)
+                       if (nid != ALC260_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -8056,16 +8086,42 @@ static struct hda_verb alc888_lenovo_sky_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb alc888_6st_dell_verbs[] = {
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
+static void alc888_3st_hp_front_automute(struct hda_codec *codec)
+{
+       unsigned int present, bits;
+
+       present = snd_hda_codec_read(codec, 0x1b, 0,
+                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       bits = present ? HDA_AMP_MUTE : 0;
+       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+       snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+}
+
+static void alc888_3st_hp_unsol_event(struct hda_codec *codec,
+                                     unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc888_3st_hp_front_automute(codec);
+               break;
+       }
+}
+
 static struct hda_verb alc888_3st_hp_verbs[] = {
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
        {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Rear : output 1 (0x0d) */
        {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},  /* CLFE : output 2 (0x0e) */
-       { }
-};
-
-static struct hda_verb alc888_6st_dell_verbs[] = {
        {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { }
+       { } /* end */
 };
 
 /*
@@ -8626,6 +8682,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
@@ -8647,6 +8704,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
        SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
@@ -8950,6 +9008,8 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc888_3st_hp_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_capture_source,
+               .unsol_event = alc888_3st_hp_unsol_event,
+               .init_hook = alc888_3st_hp_front_automute,
        },
        [ALC888_6ST_DELL] = {
                .mixers = { alc883_base_mixer, alc883_chmode_mixer },
@@ -9124,7 +9184,8 @@ static void alc883_auto_init_analog_input(struct hda_codec *codec)
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (alc883_is_input_pin(nid)) {
                        alc_set_input_pin(codec, nid, i);
-                       if (nid != ALC883_PIN_CD_NID)
+                       if (nid != ALC883_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -12816,6 +12877,27 @@ static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
 #define alc269_pcm_digital_playback    alc880_pcm_digital_playback
 #define alc269_pcm_digital_capture     alc880_pcm_digital_capture
 
+static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+       /* NID is set in alc_build_pcms */
+       .ops = {
+               .open = alc880_playback_pcm_open,
+               .prepare = alc880_playback_pcm_prepare,
+               .cleanup = alc880_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+       /* NID is set in alc_build_pcms */
+};
+
 /*
  * BIOS auto configuration
  */
@@ -13031,9 +13113,16 @@ static int patch_alc269(struct hda_codec *codec)
                setup_preset(spec, &alc269_presets[board_config]);
 
        spec->stream_name_analog = "ALC269 Analog";
-       spec->stream_analog_playback = &alc269_pcm_analog_playback;
-       spec->stream_analog_capture = &alc269_pcm_analog_capture;
-
+       if (codec->subsystem_id == 0x17aa3bf8) {
+               /* Due to a hardware problem on Lenovo Ideadpad, we need to
+                * fix the sample rate of analog I/O to 44.1kHz
+                */
+               spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
+               spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
+       } else {
+               spec->stream_analog_playback = &alc269_pcm_analog_playback;
+               spec->stream_analog_capture = &alc269_pcm_analog_capture;
+       }
        spec->stream_name_digital = "ALC269 Digital";
        spec->stream_digital_playback = &alc269_pcm_digital_playback;
        spec->stream_digital_capture = &alc269_pcm_digital_capture;
@@ -14823,7 +14912,8 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (alc861vd_is_input_pin(nid)) {
                        alc_set_input_pin(codec, nid, i);
-                       if (nid != ALC861VD_PIN_CD_NID)
+                       if (nid != ALC861VD_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                AC_VERB_SET_AMP_GAIN_MUTE,
                                                AMP_OUT_MUTE);
@@ -16668,26 +16758,58 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
        return 0;
 }
 
+/* return the index of the src widget from the connection list of the nid.
+ * return -1 if not found
+ */
+static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid,
+                               hda_nid_t src)
+{
+       hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
+       int i, conns;
+
+       conns = snd_hda_get_connections(codec, nid, conn_list,
+                                       ARRAY_SIZE(conn_list));
+       if (conns < 0)
+               return -1;
+       for (i = 0; i < conns; i++)
+               if (conn_list[i] == src)
+                       return i;
+       return -1;
+}
+
+static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
+       return (pincap & AC_PINCAP_IN) != 0;
+}
+
 /* create playback/capture controls for input pins */
-static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
+static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
+       struct alc_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (alc880_is_input_pin(cfg->input_pins[i])) {
-                       idx = alc880_input_pin_idx(cfg->input_pins[i]);
-                       err = new_analog_input(spec, cfg->input_pins[i],
-                                              auto_pin_cfg_labels[i],
-                                              idx, 0x0b);
-                       if (err < 0)
-                               return err;
-                       imux->items[imux->num_items].label =
-                               auto_pin_cfg_labels[i];
-                       imux->items[imux->num_items].index =
-                               alc880_input_pin_idx(cfg->input_pins[i]);
-                       imux->num_items++;
+               if (alc662_is_input_pin(codec, cfg->input_pins[i])) {
+                       idx = alc662_input_pin_idx(codec, 0x0b,
+                                                  cfg->input_pins[i]);
+                       if (idx >= 0) {
+                               err = new_analog_input(spec, cfg->input_pins[i],
+                                                      auto_pin_cfg_labels[i],
+                                                      idx, 0x0b);
+                               if (err < 0)
+                                       return err;
+                       }
+                       idx = alc662_input_pin_idx(codec, 0x22,
+                                                  cfg->input_pins[i]);
+                       if (idx >= 0) {
+                               imux->items[imux->num_items].label =
+                                       auto_pin_cfg_labels[i];
+                               imux->items[imux->num_items].index = idx;
+                               imux->num_items++;
+                       }
                }
        }
        return 0;
@@ -16737,7 +16859,6 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
                alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
-#define alc662_is_input_pin(nid)       alc880_is_input_pin(nid)
 #define ALC662_PIN_CD_NID              ALC880_PIN_CD_NID
 
 static void alc662_auto_init_analog_input(struct hda_codec *codec)
@@ -16747,9 +16868,10 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (alc662_is_input_pin(nid)) {
+               if (alc662_is_input_pin(codec, nid)) {
                        alc_set_input_pin(codec, nid, i);
-                       if (nid != ALC662_PIN_CD_NID)
+                       if (nid != ALC662_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -16787,7 +16909,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
                                           "Headphone");
        if (err < 0)
                return err;
-       err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -16894,7 +17016,10 @@ static int patch_alc662(struct hda_codec *codec)
 
        if (!spec->cap_mixer)
                set_capture_mixer(spec);
-       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       if (codec->vendor_id == 0x10ec0662)
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       else
+               set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
 
        spec->vmaster_nid = 0x02;