Merge branch 'topic/hda' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Thu, 27 Oct 2011 15:06:43 +0000 (17:06 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 27 Oct 2011 15:06:43 +0000 (17:06 +0200)
sound/pci/hda/hda_local.h
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c

index 46c581c..81e12c0 100644 (file)
@@ -600,7 +600,8 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 #define get_amp_nid_(pv)       ((pv) & 0xffff)
 #define get_amp_nid(kc)                get_amp_nid_((kc)->private_value)
 #define get_amp_channels(kc)   (((kc)->private_value >> 16) & 0x3)
-#define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
+#define get_amp_direction_(pv) (((pv) >> 18) & 0x1)
+#define get_amp_direction(kc)  get_amp_direction_((kc)->private_value)
 #define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
 #define get_amp_offset(kc)     (((kc)->private_value >> 23) & 0x3f)
 #define get_amp_min_mute(kc)   (((kc)->private_value >> 29) & 0x1)
index 686ec6d..0c8b5a1 100644 (file)
@@ -136,6 +136,8 @@ struct conexant_spec {
        unsigned int thinkpad:1;
        unsigned int hp_laptop:1;
        unsigned int asus:1;
+       unsigned int pin_eapd_ctrls:1;
+       unsigned int single_adc_amp:1;
 
        unsigned int adc_switching:1;
 
@@ -3430,12 +3432,14 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
 static void do_automute(struct hda_codec *codec, int num_pins,
                        hda_nid_t *pins, bool on)
 {
+       struct conexant_spec *spec = codec->spec;
        int i;
        for (i = 0; i < num_pins; i++)
                snd_hda_codec_write(codec, pins[i], 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
                                    on ? PIN_OUT : 0);
-       cx_auto_turn_eapd(codec, num_pins, pins, on);
+       if (spec->pin_eapd_ctrls)
+               cx_auto_turn_eapd(codec, num_pins, pins, on);
 }
 
 static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
@@ -3460,9 +3464,12 @@ static void cx_auto_update_speakers(struct hda_codec *codec)
        int on = 1;
 
        /* turn on HP EAPD when HP jacks are present */
-       if (spec->auto_mute)
-               on = spec->hp_present;
-       cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
+       if (spec->pin_eapd_ctrls) {
+               if (spec->auto_mute)
+                       on = spec->hp_present;
+               cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
+       }
+
        /* mute speakers in auto-mode if HP or LO jacks are plugged */
        if (spec->auto_mute)
                on = !(spec->hp_present ||
@@ -3889,20 +3896,10 @@ static void cx_auto_parse_beep(struct hda_codec *codec)
 #define cx_auto_parse_beep(codec)
 #endif
 
-static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-       int i;
-       for (i = 0; i < nums; i++)
-               if (list[i] == nid)
-                       return true;
-       return false;
-}
-
-/* parse extra-EAPD that aren't assigned to any pins */
+/* parse EAPDs */
 static void cx_auto_parse_eapd(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t nid, end_nid;
 
        end_nid = codec->start_nid + codec->num_nodes;
@@ -3911,14 +3908,18 @@ static void cx_auto_parse_eapd(struct hda_codec *codec)
                        continue;
                if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
                        continue;
-               if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) ||
-                   found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) ||
-                   found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs))
-                       continue;
                spec->eapds[spec->num_eapds++] = nid;
                if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
                        break;
        }
+
+       /* NOTE: below is a wild guess; if we have more than two EAPDs,
+        * it's a new chip, where EAPDs are supposed to be associated to
+        * pins, and we can control EAPD per pin.
+        * OTOH, if only one or two EAPDs are found, it's an old chip,
+        * thus it might control over all pins.
+        */
+       spec->pin_eapd_ctrls = spec->num_eapds > 2;
 }
 
 static int cx_auto_parse_auto_config(struct hda_codec *codec)
@@ -4024,8 +4025,9 @@ static void cx_auto_init_output(struct hda_codec *codec)
                }
        }
        cx_auto_update_speakers(codec);
-       /* turn on/off extra EAPDs, too */
-       cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
+       /* turn on all EAPDs if no individual EAPD control is available */
+       if (!spec->pin_eapd_ctrls)
+               cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
 }
 
 static void cx_auto_init_input(struct hda_codec *codec)
@@ -4212,6 +4214,8 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
                int idx = get_input_connection(codec, adc_nid, nid);
                if (idx < 0)
                        continue;
+               if (spec->single_adc_amp)
+                       idx = 0;
                return cx_auto_add_volume_idx(codec, label, pfx,
                                              cidx, adc_nid, HDA_INPUT, idx);
        }
@@ -4252,14 +4256,21 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
        struct hda_input_mux *imux = &spec->private_imux;
        const char *prev_label;
        int input_conn[HDA_MAX_NUM_INPUTS];
-       int i, err, cidx;
+       int i, j, err, cidx;
        int multi_connection;
 
+       if (!imux->num_items)
+               return 0;
+
        multi_connection = 0;
        for (i = 0; i < imux->num_items; i++) {
                cidx = get_input_connection(codec, spec->imux_info[i].adc,
                                            spec->imux_info[i].pin);
-               input_conn[i] = (spec->imux_info[i].adc << 8) | cidx;
+               if (cidx < 0)
+                       continue;
+               input_conn[i] = spec->imux_info[i].adc;
+               if (!spec->single_adc_amp)
+                       input_conn[i] |= cidx << 8;
                if (i > 0 && input_conn[i] != input_conn[0])
                        multi_connection = 1;
        }
@@ -4288,6 +4299,15 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
                        err = cx_auto_add_capture_volume(codec, nid,
                                                         "Capture", "", cidx);
                } else {
+                       bool dup_found = false;
+                       for (j = 0; j < i; j++) {
+                               if (input_conn[j] == input_conn[i]) {
+                                       dup_found = true;
+                                       break;
+                               }
+                       }
+                       if (dup_found)
+                               continue;
                        err = cx_auto_add_capture_volume(codec, nid,
                                                         label, " Capture", cidx);
                }
@@ -4412,6 +4432,12 @@ static int patch_conexant_auto(struct hda_codec *codec)
        codec->spec = spec;
        codec->pin_amp_workaround = 1;
 
+       switch (codec->vendor_id) {
+       case 0x14f15045:
+               spec->single_adc_amp = 1;
+               break;
+       }
+
        apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl);
 
        err = cx_auto_search_adcs(codec);
index 011644b..8f93b97 100644 (file)
@@ -116,6 +116,8 @@ struct alc_spec {
        const hda_nid_t *capsrc_nids;
        hda_nid_t dig_in_nid;           /* digital-in NID; optional */
        hda_nid_t mixer_nid;            /* analog-mixer NID */
+       DECLARE_BITMAP(vol_ctls, 0x20 << 1);
+       DECLARE_BITMAP(sw_ctls, 0x20 << 1);
 
        /* capture setup for dynamic dual-adc switch */
        hda_nid_t cur_adc;
@@ -3006,14 +3008,32 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
        return 0;
 }
 
+static inline unsigned int get_ctl_pos(unsigned int data)
+{
+       hda_nid_t nid = get_amp_nid_(data);
+       unsigned int dir = get_amp_direction_(data);
+       return (nid << 1) | dir;
+}
+
+#define is_ctl_used(bits, data) \
+       test_bit(get_ctl_pos(data), bits)
+#define mark_ctl_usage(bits, data) \
+       set_bit(get_ctl_pos(data), bits)
+
 static int alc_auto_add_vol_ctl(struct hda_codec *codec,
                              const char *pfx, int cidx,
                              hda_nid_t nid, unsigned int chs)
 {
+       struct alc_spec *spec = codec->spec;
+       unsigned int val;
        if (!nid)
                return 0;
+       val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
+       if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */
+               return 0;
+       mark_ctl_usage(spec->vol_ctls, val);
        return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
-                                HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+                                val);
 }
 
 #define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
@@ -3026,6 +3046,7 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
                             const char *pfx, int cidx,
                             hda_nid_t nid, unsigned int chs)
 {
+       struct alc_spec *spec = codec->spec;
        int wid_type;
        int type;
        unsigned long val;
@@ -3042,6 +3063,9 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
                type = ALC_CTL_BIND_MUTE;
                val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
        }
+       if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */
+               return 0;
+       mark_ctl_usage(spec->sw_ctls, val);
        return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
 }
 
@@ -3136,12 +3160,16 @@ static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
        int err;
 
        if (!dac) {
+               unsigned int val;
                /* the corresponding DAC is already occupied */
                if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
                        return 0; /* no way */
                /* create a switch only */
-               return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
-                                  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+               val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT);
+               if (is_ctl_used(spec->sw_ctls, val))
+                       return 0; /* already created */
+               mark_ctl_usage(spec->sw_ctls, val);
+               return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
        }
 
        sw = alc_look_for_out_mute_nid(codec, pin, dac);
@@ -3186,8 +3214,12 @@ static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
        if (!num_pins || !pins[0])
                return 0;
 
-       if (num_pins == 1)
-               return alc_auto_create_extra_out(codec, *pins, *dacs, pfx);
+       if (num_pins == 1) {
+               hda_nid_t dac = *dacs;
+               if (!dac)
+                       dac = spec->multiout.dac_nids[0];
+               return alc_auto_create_extra_out(codec, *pins, dac, pfx);
+       }
 
        if (dacs[num_pins - 1]) {
                /* OK, we have a multi-output system with individual volumes */