]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 9 Apr 2014 23:38:05 +0000 (16:38 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 9 Apr 2014 23:38:05 +0000 (16:38 -0700)
added patches:
alsa-hda-fix-internal-mic-for-lenovo-ideapad-u300s.patch

queue-3.4/alsa-hda-fix-internal-mic-for-lenovo-ideapad-u300s.patch [new file with mode: 0644]
queue-3.4/series

diff --git a/queue-3.4/alsa-hda-fix-internal-mic-for-lenovo-ideapad-u300s.patch b/queue-3.4/alsa-hda-fix-internal-mic-for-lenovo-ideapad-u300s.patch
new file mode 100644 (file)
index 0000000..b1ca1b0
--- /dev/null
@@ -0,0 +1,220 @@
+From 18dcd3044e4c4b3ab6341c98e8d0e81e0d58d5e3 Mon Sep 17 00:00:00 2001
+From: David Henningsson <david.henningsson@canonical.com>
+Date: Mon, 2 Apr 2012 15:40:27 +0200
+Subject: ALSA: hda - Fix internal mic for Lenovo Ideapad U300s
+
+From: David Henningsson <david.henningsson@canonical.com>
+
+commit 18dcd3044e4c4b3ab6341c98e8d0e81e0d58d5e3 upstream.
+
+The internal mic input is phase inverted on one channel.
+To avoid people in userspace summing the channels together
+and get zero result, use a separate mixer control for the
+inverted channel.
+
+BugLink: https://bugs.launchpad.net/bugs/903853
+Signed-off-by: David Henningsson <david.henningsson@canonical.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+[wml: Backported to 3.4:
+ - Adjust context
+ - one more enum value CXT_PINCFG_LENOVO_TP410
+ - Change both invocations of apply_pin_fixup()]
+Signed-off-by: Weng Meiling <wengmeiling.weng@huawei.com>
+---
+ sound/pci/hda/patch_conexant.c |   92 ++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 77 insertions(+), 15 deletions(-)
+
+--- a/sound/pci/hda/patch_conexant.c
++++ b/sound/pci/hda/patch_conexant.c
+@@ -141,6 +141,7 @@ struct conexant_spec {
+       unsigned int hp_laptop:1;
+       unsigned int asus:1;
+       unsigned int pin_eapd_ctrls:1;
++      unsigned int fixup_stereo_dmic:1;
+       unsigned int adc_switching:1;
+@@ -4071,9 +4072,9 @@ static int cx_auto_init(struct hda_codec
+ 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),
+@@ -4083,7 +4084,7 @@ static int cx_auto_add_volume_idx(struct
+       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;
+@@ -4102,7 +4103,7 @@ static int cx_auto_add_volume_idx(struct
+ }
+ #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)
+@@ -4172,6 +4173,36 @@ static int cx_auto_build_output_controls
+       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)
+@@ -4180,14 +4211,25 @@ static int cx_auto_add_capture_volume(st
+       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 (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;
+ }
+@@ -4200,9 +4242,19 @@ static int cx_auto_add_boost_volume(stru
+       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)
+@@ -4365,23 +4417,31 @@ static void apply_pincfg(struct hda_code
+ }
+-static void apply_pin_fixup(struct hda_codec *codec,
++enum {
++      CXT_PINCFG_LENOVO_X200,
++      CXT_PINCFG_LENOVO_TP410,
++      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,
+-      CXT_PINCFG_LENOVO_TP410,
+-};
+-
+ /* ThinkPad X200 & co with cxt5051 */
+ static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
+       { 0x16, 0x042140ff }, /* HP (seq# overridden) */
+@@ -4402,6 +4462,7 @@ static const struct cxt_pincfg cxt_pincf
+ static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
+       [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
+       [CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410,
++      [CXT_FIXUP_STEREO_DMIC] = NULL,
+ };
+ static const struct snd_pci_quirk cxt5051_fixups[] = {
+@@ -4415,6 +4476,7 @@ static const struct snd_pci_quirk cxt506
+       SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
++      SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
+       {}
+ };
+@@ -4454,11 +4516,11 @@ static int patch_conexant_auto(struct hd
+       case 0x14f15051:
+               add_cx5051_fake_mutes(codec);
+               codec->pin_amp_workaround = 1;
+-              apply_pin_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
++              apply_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
+               break;
+       default:
+               codec->pin_amp_workaround = 1;
+-              apply_pin_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
++              apply_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
+       }
+       /* Show mute-led control only on HP laptops
index 9c4f6e4e03853e689d5fc15a422526d70117e296..f8e8245cbab0c1a15095e60c8a0a85adc0814cb3 100644 (file)
@@ -53,3 +53,4 @@ alsa-hda-fix-non-snoop-page-handling.patch
 alsa-hda-add-conexant-cx20751-2-3-4-codec-support.patch
 revert-alsa-hda-shut-up-pins-at-power-saving-mode-with-conexnat-codecs.patch
 alsa-hda-always-turn-on-pins-for-hdmi-dp.patch
+alsa-hda-fix-internal-mic-for-lenovo-ideapad-u300s.patch