Merge branch 'fix/hda' into topic/hda
authorTakashi Iwai <tiwai@suse.de>
Sat, 7 Apr 2012 10:26:55 +0000 (12:26 +0200)
committerTakashi Iwai <tiwai@suse.de>
Sat, 7 Apr 2012 10:26:55 +0000 (12:26 +0200)
Conflicts:
sound/pci/hda/patch_conexant.c

1  2 
sound/pci/hda/patch_conexant.c

@@@ -141,8 -141,6 +141,7 @@@ struct conexant_spec 
        unsigned int hp_laptop:1;
        unsigned int asus:1;
        unsigned int pin_eapd_ctrls:1;
-       unsigned int single_adc_amp:1;
 +      unsigned int fixup_stereo_dmic:1;
  
        unsigned int adc_switching:1;
  
@@@ -688,27 -686,26 +687,26 @@@ static const struct hda_channel_mode cx
  static const struct hda_input_mux cxt5045_capture_source = {
        .num_items = 2,
        .items = {
-               { "IntMic", 0x1 },
-               { "ExtMic", 0x2 },
+               { "Internal Mic", 0x1 },
+               { "Mic",          0x2 },
        }
  };
  
  static const struct hda_input_mux cxt5045_capture_source_benq = {
-       .num_items = 5,
+       .num_items = 4,
        .items = {
-               { "IntMic", 0x1 },
-               { "ExtMic", 0x2 },
-               { "LineIn", 0x3 },
-               { "CD",     0x4 },
-               { "Mixer",  0x0 },
+               { "Internal Mic", 0x1 },
+               { "Mic",          0x2 },
+               { "Line",         0x3 },
+               { "Mixer",        0x0 },
        }
  };
  
  static const struct hda_input_mux cxt5045_capture_source_hp530 = {
        .num_items = 2,
        .items = {
-               { "ExtMic", 0x1 },
-               { "IntMic", 0x2 },
+               { "Mic",          0x1 },
+               { "Internal Mic", 0x2 },
        }
  };
  
@@@ -799,10 -796,8 +797,8 @@@ static void cxt5045_hp_unsol_event(stru
  }
  
  static const struct snd_kcontrol_new cxt5045_mixers[] = {
-       HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
  };
  
  static const struct snd_kcontrol_new cxt5045_benq_mixers[] = {
-       HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x4, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mixer Capture Volume", 0x1a, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mixer Capture Switch", 0x1a, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x3, HDA_INPUT),
  
        {}
  };
  
  static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
-       HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
@@@ -947,10 -930,10 +931,10 @@@ static const struct snd_kcontrol_new cx
        /* Output controls */
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Node 11 Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Node 11 Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Node 12 Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Node 12 Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("HP-OUT Playback Volume", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("HP-OUT Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("LINE1 Playback Switch", 0x12, 0x0, HDA_OUTPUT),
        
        /* Modes for retasking pin widgets */
        CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT),
  
        /* Loopback mixer controls */
  
-       HDA_CODEC_VOLUME("Mixer-1 Volume", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mixer-1 Switch", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mixer-2 Volume", 0x17, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Mixer-2 Switch", 0x17, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mixer-3 Volume", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("Mixer-3 Switch", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mixer-4 Volume", 0x17, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("Mixer-4 Switch", 0x17, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mixer-5 Volume", 0x17, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Mixer-5 Switch", 0x17, 0x4, HDA_INPUT),
+       HDA_CODEC_VOLUME("PCM Volume", 0x17, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("PCM Switch", 0x17, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("MIC1 pin Volume", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("MIC1 pin Switch", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("LINE1 pin Volume", 0x17, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("LINE1 pin Switch", 0x17, 0x2, HDA_INPUT),
+       HDA_CODEC_VOLUME("HP-OUT pin Volume", 0x17, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("HP-OUT pin Switch", 0x17, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD pin Volume", 0x17, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("CD pin Switch", 0x17, 0x4, HDA_INPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Input Source",
                .put = conexant_mux_enum_put,
        },
        /* Audio input controls */
-       HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT),
        { } /* end */
  };
  
@@@ -1010,10 -985,6 +986,6 @@@ static const struct hda_verb cxt5045_te
        {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0},
  
-       /* Start with output sum widgets muted and their output gains at min */
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
        /* Unmute retasking pin widget output buffers since the default
         * state appears to be output.  As the pin mode is changed by the
         * user the pin mode control will take care of enabling the pin's
        /* Set ADC connection select to match default mixer setting (mic1
         * pin)
         */
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x01},
  
        /* Mute all inputs to mixer widget (even unconnected ones) */
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer */
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */
@@@ -1111,7 -1082,7 +1083,7 @@@ static int patch_cxt5045(struct hda_cod
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
-       codec->pin_amp_workaround = 1;
+       codec->single_adc_amp = 1;
  
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids);
@@@ -1636,7 -1607,7 +1608,7 @@@ static void cxt5051_update_speaker(stru
        pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
        snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                            pinctl);
 -      /* on ideapad there is an aditional speaker (subwoofer) to mute */
 +      /* on ideapad there is an additional speaker (subwoofer) to mute */
        if (spec->ideapad)
                snd_hda_codec_write(codec, 0x1b, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
@@@ -4108,9 -4079,9 +4080,9 @@@ static int cx_auto_init(struct hda_code
  
  static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
                              const char *dir, int cidx,
 -                            hda_nid_t nid, int hda_dir, int amp_idx)
 +                            hda_nid_t nid, int hda_dir, int amp_idx, int chs)
  {
 -      static char name[32];
 +      static char name[44];
        static struct snd_kcontrol_new knew[] = {
                HDA_CODEC_VOLUME(name, 0, 0, 0),
                HDA_CODEC_MUTE(name, 0, 0, 0),
  
        for (i = 0; i < 2; i++) {
                struct snd_kcontrol *kctl;
 -              knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
 +              knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx,
                                                            hda_dir);
                knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
                knew[i].index = cidx;
  }
  
  #define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir)               \
 -      cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
 +      cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3)
  
  #define cx_auto_add_pb_volume(codec, nid, str, idx)                   \
        cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
@@@ -4209,36 -4180,6 +4181,36 @@@ static int cx_auto_build_output_control
        return 0;
  }
  
 +/* Returns zero if this is a normal stereo channel, and non-zero if it should
 +   be split in two independent channels.
 +   dest_label must be at least 44 characters. */
 +static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label,
 +                                   char *dest_label, int nid)
 +{
 +      struct conexant_spec *spec = codec->spec;
 +      int i;
 +
 +      if (!spec->fixup_stereo_dmic)
 +              return 0;
 +
 +      for (i = 0; i < AUTO_CFG_MAX_INS; i++) {
 +              int def_conf;
 +              if (spec->autocfg.inputs[i].pin != nid)
 +                      continue;
 +
 +              if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC)
 +                      return 0;
 +              def_conf = snd_hda_codec_get_pincfg(codec, nid);
 +              if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT)
 +                      return 0;
 +
 +              /* Finally found the inverted internal mic! */
 +              snprintf(dest_label, 44, "Inverted %s", label);
 +              return 1;
 +      }
 +      return 0;
 +}
 +
  static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
                                      const char *label, const char *pfx,
                                      int cidx)
        int i;
  
        for (i = 0; i < spec->num_adc_nids; i++) {
 +              char rightch_label[44];
                hda_nid_t adc_nid = spec->adc_nids[i];
                int idx = get_input_connection(codec, adc_nid, nid);
                if (idx < 0)
                        continue;
-               if (spec->single_adc_amp)
+               if (codec->single_adc_amp)
                        idx = 0;
 +
 +              if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
 +                      /* Make two independent kcontrols for left and right */
 +                      int err = cx_auto_add_volume_idx(codec, label, pfx,
 +                                            cidx, adc_nid, HDA_INPUT, idx, 1);
 +                      if (err < 0)
 +                              return err;
 +                      return cx_auto_add_volume_idx(codec, rightch_label, pfx,
 +                                                    cidx, adc_nid, HDA_INPUT, idx, 2);
 +              }
                return cx_auto_add_volume_idx(codec, label, pfx,
 -                                            cidx, adc_nid, HDA_INPUT, idx);
 +                                            cidx, adc_nid, HDA_INPUT, idx, 3);
        }
        return 0;
  }
@@@ -4278,19 -4208,9 +4250,19 @@@ static int cx_auto_add_boost_volume(str
        int i, con;
  
        nid = spec->imux_info[idx].pin;
 -      if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
 +      if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
 +              char rightch_label[44];
 +              if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
 +                      int err = cx_auto_add_volume_idx(codec, label, " Boost",
 +                                                       cidx, nid, HDA_INPUT, 0, 1);
 +                      if (err < 0)
 +                              return err;
 +                      return cx_auto_add_volume_idx(codec, rightch_label, " Boost",
 +                                                    cidx, nid, HDA_INPUT, 0, 2);
 +              }
                return cx_auto_add_volume(codec, label, " Boost", cidx,
                                          nid, HDA_INPUT);
 +      }
        con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
                                        &mux, false, 0);
        if (con < 0)
@@@ -4327,7 -4247,7 +4299,7 @@@ static int cx_auto_build_input_controls
                if (cidx < 0)
                        continue;
                input_conn[i] = spec->imux_info[i].adc;
-               if (!spec->single_adc_amp)
+               if (!codec->single_adc_amp)
                        input_conn[i] |= cidx << 8;
                if (i > 0 && input_conn[i] != input_conn[0])
                        multi_connection = 1;
@@@ -4457,30 -4377,22 +4429,30 @@@ static void apply_pincfg(struct hda_cod
  
  }
  
 -static void apply_pin_fixup(struct hda_codec *codec,
 +enum {
 +      CXT_PINCFG_LENOVO_X200,
 +      CXT_FIXUP_STEREO_DMIC,
 +};
 +
 +static void apply_fixup(struct hda_codec *codec,
                            const struct snd_pci_quirk *quirk,
                            const struct cxt_pincfg **table)
  {
 +      struct conexant_spec *spec = codec->spec;
 +
        quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
 -      if (quirk) {
 +      if (quirk && table[quirk->value]) {
                snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n",
                            quirk->name);
                apply_pincfg(codec, table[quirk->value]);
        }
 +      if (quirk->value == CXT_FIXUP_STEREO_DMIC) {
 +              snd_printdd(KERN_INFO "hda_codec: applying internal mic workaround for %s\n",
 +                          quirk->name);
 +              spec->fixup_stereo_dmic = 1;
 +      }
  }
  
 -enum {
 -      CXT_PINCFG_LENOVO_X200,
 -};
 -
  static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
        { 0x16, 0x042140ff }, /* HP (seq# overridden) */
        { 0x17, 0x21a11000 }, /* dock-mic */
  
  static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
        [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
 +      [CXT_FIXUP_STEREO_DMIC] = NULL,
  };
  
  static const struct snd_pci_quirk cxt_fixups[] = {
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
 +      SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
        {}
  };
  
@@@ -4528,18 -4438,20 +4500,20 @@@ static int patch_conexant_auto(struct h
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
-       codec->pin_amp_workaround = 1;
  
        switch (codec->vendor_id) {
        case 0x14f15045:
-               spec->single_adc_amp = 1;
+               codec->single_adc_amp = 1;
                break;
        case 0x14f15051:
                add_cx5051_fake_mutes(codec);
+               codec->pin_amp_workaround = 1;
                break;
+       default:
+               codec->pin_amp_workaround = 1;
        }
  
 -      apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl);
 +      apply_fixup(codec, cxt_fixups, cxt_pincfg_tbl);
  
        /* Show mute-led control only on HP laptops
         * This is a sort of white-list: on HP laptops, EAPD corresponds