ALSA: hda - Add auto-parser support to cxt5045 / CX20549 Venice
authorTakashi Iwai <tiwai@suse.de>
Fri, 13 May 2011 15:22:05 +0000 (17:22 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 13 May 2011 15:22:05 +0000 (17:22 +0200)
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_conexant.c

index cdb9f49..623cd9b 100644 (file)
@@ -1059,6 +1059,7 @@ enum {
 #ifdef CONFIG_SND_DEBUG
        CXT5045_TEST,
 #endif
+       CXT5045_AUTO,
        CXT5045_MODELS
 };
 
@@ -1071,6 +1072,7 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
 #ifdef CONFIG_SND_DEBUG
        [CXT5045_TEST]          = "test",
 #endif
+       [CXT5045_AUTO]                  = "auto",
 };
 
 static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
@@ -1097,6 +1099,14 @@ static int patch_cxt5045(struct hda_codec *codec)
        struct conexant_spec *spec;
        int board_config;
 
+       board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
+                                                 cxt5045_models,
+                                                 cxt5045_cfg_tbl);
+       if (board_config < 0)
+               board_config = CXT5045_AUTO;
+       if (board_config == CXT5045_AUTO)
+               return patch_conexant_auto(codec);
+
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
                return -ENOMEM;
@@ -1123,9 +1133,6 @@ static int patch_cxt5045(struct hda_codec *codec)
 
        codec->patch_ops = conexant_patch_ops;
 
-       board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
-                                                 cxt5045_models,
-                                                 cxt5045_cfg_tbl);
        switch (board_config) {
        case CXT5045_LAPTOP_HPSENSE:
                codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
@@ -1956,11 +1963,8 @@ static int patch_cxt5051(struct hda_codec *codec)
                                                  cxt5051_cfg_tbl);
        if (board_config < 0)
                board_config = CXT5051_AUTO;
-       if (board_config == CXT5051_AUTO) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
+       if (board_config == CXT5051_AUTO)
                return patch_conexant_auto(codec);
-       }
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
@@ -3688,15 +3692,15 @@ static void select_connection(struct hda_codec *codec, hda_nid_t pin,
                                    AC_VERB_SET_CONNECT_SEL, idx);
 }
 
-static void cx_auto_init_output(struct hda_codec *codec)
+static void mute_outputs(struct hda_codec *codec, int num_nids,
+                        const hda_nid_t *nids)
 {
-       struct conexant_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t nid;
        int i, val;
 
-       for (i = 0; i < spec->multiout.num_dacs; i++) {
-               nid = spec->multiout.dac_nids[i];
+       for (i = 0; i < num_nids; i++) {
+               hda_nid_t nid = nids[i];
+               if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
+                       continue;
                if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE)
                        val = AMP_OUT_MUTE;
                else
@@ -3704,10 +3708,22 @@ static void cx_auto_init_output(struct hda_codec *codec)
                snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_AMP_GAIN_MUTE, val);
        }
+}
 
+static void cx_auto_init_output(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid;
+       int i;
+
+       mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids);
        for (i = 0; i < cfg->hp_outs; i++)
                snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+       mute_outputs(codec, cfg->hp_outs, cfg->hp_pins);
+       mute_outputs(codec, cfg->line_outs, cfg->line_out_pins);
+       mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins);
        if (spec->auto_mute) {
                for (i = 0; i < cfg->hp_outs; i++) {
                        snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
@@ -3747,6 +3763,8 @@ static void cx_auto_init_input(struct hda_codec *codec)
 
        for (i = 0; i < spec->num_adc_nids; i++) {
                hda_nid_t nid = spec->adc_nids[i];
+               if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+                       continue;
                if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)
                        val = AMP_IN_MUTE(0);
                else
@@ -3839,6 +3857,19 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
 #define cx_auto_add_pb_volume(codec, nid, str, idx)                    \
        cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
 
+static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac,
+                            hda_nid_t pin, const char *name, int idx)
+{
+       unsigned int caps;
+       caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+       if (caps & AC_AMPCAP_NUM_STEPS)
+               return cx_auto_add_pb_volume(codec, dac, name, idx);
+       caps = query_amp_caps(codec, pin, HDA_OUTPUT);
+       if (caps & AC_AMPCAP_NUM_STEPS)
+               return cx_auto_add_pb_volume(codec, pin, name, idx);
+       return 0;
+}
+
 static int cx_auto_build_output_controls(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
@@ -3847,8 +3878,10 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
        static const char * const texts[3] = { "Front", "Surround", "CLFE" };
 
        if (spec->dac_info_filled == 1)
-               return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
-                                            "Master", 0);
+               return try_add_pb_volume(codec, spec->dac_info[0].dac,
+                                        spec->dac_info[0].pin,
+                                        "Master", 0);
+
        for (i = 0; i < spec->dac_info_filled; i++) {
                const char *label;
                int idx, type;
@@ -3872,8 +3905,9 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
                        idx = num_spk++;
                        break;
                }
-               err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac,
-                                           label, idx);
+               err = try_add_pb_volume(codec, spec->dac_info[i].dac,
+                                       spec->dac_info[i].pin,
+                                       label, idx);
                if (err < 0)
                        return err;
        }
@@ -3976,19 +4010,31 @@ static int patch_conexant_auto(struct hda_codec *codec)
        struct conexant_spec *spec;
        int err;
 
+       printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+              codec->chip_name);
+
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
-       if (codec->vendor_id == 0x14f15051) {
+       switch (codec->vendor_id) {
+       case 0x14f15051:
                codec->pin_amp_workaround = 1;
                spec->adc_nids = cxt5051_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(cxt5051_adc_nids);
                spec->capsrc_nids = spec->adc_nids;
-       } else {
+               break;
+       case 0x14f15045:
+               codec->pin_amp_workaround = 1;
+               spec->adc_nids = cxt5045_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(cxt5045_adc_nids);
+               spec->capsrc_nids = spec->adc_nids;
+               break;
+       default:
                spec->adc_nids = cx_auto_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
                spec->capsrc_nids = spec->adc_nids;
+               break;
        }
        err = cx_auto_parse_auto_config(codec);
        if (err < 0) {