summaryrefslogtreecommitdiff
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_auto_parser.c1
-rw-r--r--sound/pci/hda/hda_codec.c4
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_generic.c9
-rw-r--r--sound/pci/hda/hda_generic.h1
-rw-r--r--sound/pci/hda/hda_intel.c139
-rw-r--r--sound/pci/hda/patch_ca0132.c10
-rw-r--r--sound/pci/hda/patch_conexant.c81
-rw-r--r--sound/pci/hda/patch_hdmi.c29
-rw-r--r--sound/pci/hda/patch_realtek.c221
10 files changed, 466 insertions, 30 deletions
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index a03cf68d0bcd..d3ea73171a3d 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -580,6 +580,7 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec,
has_multiple_pins = 1;
if (has_multiple_pins && type == AUTO_PIN_MIC)
has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+ has_multiple_pins |= codec->force_pin_prefix;
return hda_get_input_pin_label(codec, &cfg->inputs[input],
cfg->inputs[input].pin,
has_multiple_pins);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 8fd745cb3f36..70bb365a08d2 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1965,7 +1965,7 @@ static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static struct snd_kcontrol_new vmaster_mute_mode = {
+static const struct snd_kcontrol_new vmaster_mute_mode = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mute-LED Mode",
.info = vmaster_mute_mode_info,
@@ -2705,7 +2705,7 @@ static int spdif_share_sw_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new spdif_share_sw = {
+static const struct snd_kcontrol_new spdif_share_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Default PCM Playback Switch",
.info = snd_ctl_boolean_mono_info,
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index f17f25245e52..d6fb2d5d01a7 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -256,6 +256,7 @@ struct hda_codec {
unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
unsigned int power_save_node:1; /* advanced PM for each widget */
unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */
+ unsigned int force_pin_prefix:1; /* Add location prefix */
#ifdef CONFIG_PM
unsigned long power_on_acct;
unsigned long power_off_acct;
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index e7c8f4f076d5..2842c82363c0 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -196,6 +196,9 @@ static void parse_user_hints(struct hda_codec *codec)
val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
if (val >= 0)
spec->suppress_hp_mic_detect = !val;
+ val = snd_hda_get_bool_hint(codec, "vmaster");
+ if (val >= 0)
+ spec->suppress_vmaster = !val;
if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
spec->mixer_nid = val;
@@ -1125,6 +1128,7 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
*index = 0;
if (cfg->line_outs == 1 && !spec->multi_ios &&
+ !codec->force_pin_prefix &&
!cfg->hp_outs && !cfg->speaker_outs)
return spec->vmaster_mute.hook ? "PCM" : "Master";
@@ -1132,6 +1136,7 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
* use it master (or "PCM" if a vmaster hook is present)
*/
if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
+ !codec->force_pin_prefix &&
!spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
return spec->vmaster_mute.hook ? "PCM" : "Master";
@@ -5031,7 +5036,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
}
/* if we have no master control, let's create it */
- if (!spec->no_analog &&
+ if (!spec->no_analog && !spec->suppress_vmaster &&
!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
spec->vmaster_tlv, slave_pfxs,
@@ -5039,7 +5044,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
}
- if (!spec->no_analog &&
+ if (!spec->no_analog && !spec->suppress_vmaster &&
!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
NULL, slave_pfxs,
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index f66fc7e25e07..61772317de46 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -229,6 +229,7 @@ struct hda_gen_spec {
unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
unsigned int power_down_unused:1; /* power down unused widgets */
unsigned int dac_min_mute:1; /* minimal = mute for DACs */
+ unsigned int suppress_vmaster:1; /* don't create vmaster kctls */
/* other internal flags */
unsigned int no_analog:1; /* digital I/O only */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c8256a89375a..b786fbab029f 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -77,6 +77,7 @@ enum {
POS_FIX_POSBUF,
POS_FIX_VIACOMBO,
POS_FIX_COMBO,
+ POS_FIX_SKL,
};
/* Defines for ATI HD Audio support in SB450 south bridge */
@@ -148,7 +149,7 @@ module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model.");
module_param_array(position_fix, int, NULL, 0444);
MODULE_PARM_DESC(position_fix, "DMA pointer read method."
- "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
+ "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+).");
module_param_array(bdl_pos_adj, int, NULL, 0644);
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
module_param_array(probe_mask, int, NULL, 0444);
@@ -369,8 +370,10 @@ enum {
#define IS_KBL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d71)
#define IS_KBL_H(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa2f0)
#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
+#define IS_GLK(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x3198)
#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) || \
- IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci)
+ IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci) || \
+ IS_GLK(pci)
static char *driver_short_names[] = {
[AZX_DRIVER_ICH] = "HDA Intel",
@@ -534,9 +537,101 @@ static void bxt_reduce_dma_latency(struct azx *chip)
{
u32 val;
- val = azx_readl(chip, SKL_EM4L);
+ val = azx_readl(chip, VS_EM4L);
val &= (0x3 << 20);
- azx_writel(chip, SKL_EM4L, val);
+ azx_writel(chip, VS_EM4L, val);
+}
+
+/*
+ * ML_LCAP bits:
+ * bit 0: 6 MHz Supported
+ * bit 1: 12 MHz Supported
+ * bit 2: 24 MHz Supported
+ * bit 3: 48 MHz Supported
+ * bit 4: 96 MHz Supported
+ * bit 5: 192 MHz Supported
+ */
+static int intel_get_lctl_scf(struct azx *chip)
+{
+ struct hdac_bus *bus = azx_bus(chip);
+ static int preferred_bits[] = { 2, 3, 1, 4, 5 };
+ u32 val, t;
+ int i;
+
+ val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCAP);
+
+ for (i = 0; i < ARRAY_SIZE(preferred_bits); i++) {
+ t = preferred_bits[i];
+ if (val & (1 << t))
+ return t;
+ }
+
+ dev_warn(chip->card->dev, "set audio clock frequency to 6MHz");
+ return 0;
+}
+
+static int intel_ml_lctl_set_power(struct azx *chip, int state)
+{
+ struct hdac_bus *bus = azx_bus(chip);
+ u32 val;
+ int timeout;
+
+ /*
+ * the codecs are sharing the first link setting by default
+ * If other links are enabled for stream, they need similar fix
+ */
+ val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
+ val &= ~AZX_MLCTL_SPA;
+ val |= state << AZX_MLCTL_SPA_SHIFT;
+ writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
+ /* wait for CPA */
+ timeout = 50;
+ while (timeout) {
+ if (((readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL)) &
+ AZX_MLCTL_CPA) == (state << AZX_MLCTL_CPA_SHIFT))
+ return 0;
+ timeout--;
+ udelay(10);
+ }
+
+ return -1;
+}
+
+static void intel_init_lctl(struct azx *chip)
+{
+ struct hdac_bus *bus = azx_bus(chip);
+ u32 val;
+ int ret;
+
+ /* 0. check lctl register value is correct or not */
+ val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
+ /* if SCF is already set, let's use it */
+ if ((val & ML_LCTL_SCF_MASK) != 0)
+ return;
+
+ /*
+ * Before operating on SPA, CPA must match SPA.
+ * Any deviation may result in undefined behavior.
+ */
+ if (((val & AZX_MLCTL_SPA) >> AZX_MLCTL_SPA_SHIFT) !=
+ ((val & AZX_MLCTL_CPA) >> AZX_MLCTL_CPA_SHIFT))
+ return;
+
+ /* 1. turn link down: set SPA to 0 and wait CPA to 0 */
+ ret = intel_ml_lctl_set_power(chip, 0);
+ udelay(100);
+ if (ret)
+ goto set_spa;
+
+ /* 2. update SCF to select a properly audio clock*/
+ val &= ~ML_LCTL_SCF_MASK;
+ val |= intel_get_lctl_scf(chip);
+ writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
+
+set_spa:
+ /* 4. turn link up: set SPA to 1 and wait CPA to 1 */
+ intel_ml_lctl_set_power(chip, 1);
+ udelay(100);
}
static void hda_intel_init_chip(struct azx *chip, bool full_reset)
@@ -564,6 +659,9 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
/* reduce dma latency to avoid noise */
if (IS_BXT(pci))
bxt_reduce_dma_latency(chip);
+
+ if (bus->mlcap != NULL)
+ intel_init_lctl(chip);
}
/* calculate runtime delay from LPIB */
@@ -815,6 +913,31 @@ static unsigned int azx_via_get_position(struct azx *chip,
return bound_pos + mod_dma_pos;
}
+static unsigned int azx_skl_get_dpib_pos(struct azx *chip,
+ struct azx_dev *azx_dev)
+{
+ return _snd_hdac_chip_readl(azx_bus(chip),
+ AZX_REG_VS_SDXDPIB_XBASE +
+ (AZX_REG_VS_SDXDPIB_XINTERVAL *
+ azx_dev->core.index));
+}
+
+/* get the current DMA position with correction on SKL+ chips */
+static unsigned int azx_get_pos_skl(struct azx *chip, struct azx_dev *azx_dev)
+{
+ /* DPIB register gives a more accurate position for playback */
+ if (azx_dev->core.substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return azx_skl_get_dpib_pos(chip, azx_dev);
+
+ /* For capture, we need to read posbuf, but it requires a delay
+ * for the possible boundary overlap; the read of DPIB fetches the
+ * actual posbuf
+ */
+ udelay(20);
+ azx_skl_get_dpib_pos(chip, azx_dev);
+ return azx_get_pos_posbuf(chip, azx_dev);
+}
+
#ifdef CONFIG_PM
static DEFINE_MUTEX(card_list_lock);
static LIST_HEAD(card_list);
@@ -1351,6 +1474,7 @@ static int check_position_fix(struct azx *chip, int fix)
case POS_FIX_POSBUF:
case POS_FIX_VIACOMBO:
case POS_FIX_COMBO:
+ case POS_FIX_SKL:
return fix;
}
@@ -1371,6 +1495,10 @@ static int check_position_fix(struct azx *chip, int fix)
dev_dbg(chip->card->dev, "Using LPIB position fix\n");
return POS_FIX_LPIB;
}
+ if (IS_SKL_PLUS(chip->pci)) {
+ dev_dbg(chip->card->dev, "Using SKL position fix\n");
+ return POS_FIX_SKL;
+ }
return POS_FIX_AUTO;
}
@@ -1382,6 +1510,7 @@ static void assign_position_fix(struct azx *chip, int fix)
[POS_FIX_POSBUF] = azx_get_pos_posbuf,
[POS_FIX_VIACOMBO] = azx_via_get_position,
[POS_FIX_COMBO] = azx_get_pos_lpib,
+ [POS_FIX_SKL] = azx_get_pos_skl,
};
chip->get_position[0] = chip->get_position[1] = callbacks[fix];
@@ -1390,7 +1519,7 @@ static void assign_position_fix(struct azx *chip, int fix)
if (fix == POS_FIX_COMBO)
chip->get_position[1] = NULL;
- if (fix == POS_FIX_POSBUF &&
+ if ((fix == POS_FIX_POSBUF || fix == POS_FIX_SKL) &&
(chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
chip->get_delay[0] = chip->get_delay[1] =
azx_get_delay_from_lpib;
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 07a9deb17477..a148176c16a9 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -857,7 +857,7 @@ static int chipio_write_address(struct hda_codec *codec,
chip_addx >> 16);
}
- spec->curr_chip_addx = (res < 0) ? ~0UL : chip_addx;
+ spec->curr_chip_addx = (res < 0) ? ~0U : chip_addx;
return res;
}
@@ -882,7 +882,7 @@ static int chipio_write_data(struct hda_codec *codec, unsigned int data)
/*If no error encountered, automatically increment the address
as per chip behaviour*/
spec->curr_chip_addx = (res != -EIO) ?
- (spec->curr_chip_addx + 4) : ~0UL;
+ (spec->curr_chip_addx + 4) : ~0U;
return res;
}
@@ -933,7 +933,7 @@ static int chipio_read_data(struct hda_codec *codec, unsigned int *data)
/*If no error encountered, automatically increment the address
as per chip behaviour*/
spec->curr_chip_addx = (res != -EIO) ?
- (spec->curr_chip_addx + 4) : ~0UL;
+ (spec->curr_chip_addx + 4) : ~0U;
return res;
}
@@ -1168,7 +1168,7 @@ static int dspio_write_multiple(struct hda_codec *codec,
int status = 0;
unsigned int count;
- if ((buffer == NULL))
+ if (buffer == NULL)
return -EINVAL;
count = 0;
@@ -1210,7 +1210,7 @@ static int dspio_read_multiple(struct hda_codec *codec, unsigned int *buffer,
unsigned int skip_count;
unsigned int dummy;
- if ((buffer == NULL))
+ if (buffer == NULL)
return -1;
count = 0;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 69266b8ea2ad..e8253737c47a 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -52,6 +52,12 @@ struct conexant_spec {
bool dc_enable;
unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
struct nid_path *dc_mode_path;
+
+ int mute_led_polarity;
+ unsigned int gpio_led;
+ unsigned int gpio_mute_led_mask;
+ unsigned int gpio_mic_led_mask;
+
};
@@ -264,6 +270,7 @@ enum {
CXT_FIXUP_HP_DOCK,
CXT_FIXUP_HP_SPECTRE,
CXT_FIXUP_HP_GATE_MIC,
+ CXT_FIXUP_MUTE_LED_GPIO,
};
/* for hda_fixup_thinkpad_acpi() */
@@ -646,6 +653,74 @@ static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
}
+/* update LED status via GPIO */
+static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+ bool enabled)
+{
+ struct conexant_spec *spec = codec->spec;
+ unsigned int oldval = spec->gpio_led;
+
+ if (spec->mute_led_polarity)
+ enabled = !enabled;
+
+ if (enabled)
+ spec->gpio_led &= ~mask;
+ else
+ spec->gpio_led |= mask;
+ if (spec->gpio_led != oldval)
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_led);
+}
+
+/* turn on/off mute LED via GPIO per vmaster hook */
+static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled)
+{
+ struct hda_codec *codec = private_data;
+ struct conexant_spec *spec = codec->spec;
+
+ cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled);
+}
+
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static void cxt_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct conexant_spec *spec = codec->spec;
+
+ if (ucontrol)
+ cxt_update_gpio_led(codec, spec->gpio_mic_led_mask,
+ ucontrol->value.integer.value[0] ||
+ ucontrol->value.integer.value[1]);
+}
+
+
+static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct conexant_spec *spec = codec->spec;
+ static const struct hda_verb gpio_init[] = {
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x03 },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
+ {}
+ };
+ codec_info(codec, "action: %d gpio_led: %d\n", action, spec->gpio_led);
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook;
+ spec->gen.cap_sync_hook = cxt_fixup_gpio_mic_mute_hook;
+ spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x01;
+ spec->gpio_mic_led_mask = 0x02;
+ }
+ snd_hda_add_verbs(codec, gpio_init);
+ if (spec->gpio_led)
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_led);
+}
+
+
/* ThinkPad X200 & co with cxt5051 */
static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
@@ -799,6 +874,10 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_hp_gate_mic_jack,
},
+ [CXT_FIXUP_MUTE_LED_GPIO] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cxt_fixup_mute_led_gpio,
+ },
};
static const struct snd_pci_quirk cxt5045_fixups[] = {
@@ -851,6 +930,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
+ SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
@@ -882,6 +962,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
{ .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
{ .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
{ .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
+ { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
{}
};
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 1461ef8eb749..90e4ff87445e 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -177,6 +177,7 @@ struct hdmi_spec {
bool i915_bound; /* was i915 bound in this driver? */
struct hdac_chmap chmap;
+ hda_nid_t vendor_nid;
};
#ifdef CONFIG_SND_HDA_I915
@@ -383,7 +384,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new eld_bytes_ctl = {
+static const struct snd_kcontrol_new eld_bytes_ctl = {
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "ELD",
@@ -2372,6 +2373,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
}
#define INTEL_VENDOR_NID 0x08
+#define INTEL_GLK_VENDOR_NID 0x0B
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
@@ -2381,14 +2383,15 @@ static void intel_haswell_enable_all_pins(struct hda_codec *codec,
bool update_tree)
{
unsigned int vendor_param;
+ struct hdmi_spec *spec = codec->spec;
- vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
+ vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
return;
vendor_param |= INTEL_EN_ALL_PIN_CVTS;
- vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
+ vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1)
return;
@@ -2400,8 +2403,9 @@ static void intel_haswell_enable_all_pins(struct hda_codec *codec,
static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
{
unsigned int vendor_param;
+ struct hdmi_spec *spec = codec->spec;
- vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
+ vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
return;
@@ -2409,7 +2413,7 @@ static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
/* enable DP1.2 mode */
vendor_param |= INTEL_EN_DP12;
snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
- snd_hda_codec_write_cache(codec, INTEL_VENDOR_NID, 0,
+ snd_hda_codec_write_cache(codec, spec->vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
}
@@ -2503,7 +2507,7 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec,
}
/* Intel Haswell and onwards; audio component with eld notifier */
-static int patch_i915_hsw_hdmi(struct hda_codec *codec)
+static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid)
{
struct hdmi_spec *spec;
int err;
@@ -2520,6 +2524,7 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec)
spec = codec->spec;
codec->dp_mst = true;
spec->dyn_pcm_assign = true;
+ spec->vendor_nid = vendor_nid;
intel_haswell_enable_all_pins(codec, true);
intel_haswell_fixup_enable_dp12(codec);
@@ -2548,6 +2553,16 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec)
return 0;
}
+static int patch_i915_hsw_hdmi(struct hda_codec *codec)
+{
+ return intel_hsw_common_init(codec, INTEL_VENDOR_NID);
+}
+
+static int patch_i915_glk_hdmi(struct hda_codec *codec)
+{
+ return intel_hsw_common_init(codec, INTEL_GLK_VENDOR_NID);
+}
+
/* Intel Baytrail and Braswell; with eld notifier */
static int patch_i915_byt_hdmi(struct hda_codec *codec)
{
@@ -3800,7 +3815,7 @@ HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi),
HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 299835d1fbaa..58df440013c5 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1800,6 +1800,7 @@ enum {
ALC882_FIXUP_NO_PRIMARY_HP,
ALC887_FIXUP_ASUS_BASS,
ALC887_FIXUP_BASS_CHMAP,
+ ALC1220_FIXUP_GB_DUAL_CODECS,
};
static void alc889_fixup_coef(struct hda_codec *codec,
@@ -1962,6 +1963,61 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
static void alc_fixup_bass_chmap(struct hda_codec *codec,
const struct hda_fixup *fix, int action);
+/* For dual-codec configuration, we need to disable some features to avoid
+ * conflicts of kctls and PCM streams
+ */
+static void alc_fixup_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ /* disable vmaster */
+ spec->gen.suppress_vmaster = 1;
+ /* auto-mute and auto-mic switch don't work with multiple codecs */
+ spec->gen.suppress_auto_mute = 1;
+ spec->gen.suppress_auto_mic = 1;
+ /* disable aamix as well */
+ spec->gen.mixer_nid = 0;
+ /* add location prefix to avoid conflicts */
+ codec->force_pin_prefix = 1;
+}
+
+static void rename_ctl(struct hda_codec *codec, const char *oldname,
+ const char *newname)
+{
+ struct snd_kcontrol *kctl;
+
+ kctl = snd_hda_find_mixer_ctl(codec, oldname);
+ if (kctl)
+ strcpy(kctl->id.name, newname);
+}
+
+static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ alc_fixup_dual_codecs(codec, fix, action);
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /* override card longname to provide a unique UCM profile */
+ strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ /* rename Capture controls depending on the codec */
+ rename_ctl(codec, "Capture Volume",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Volume" :
+ "Front-Panel Capture Volume");
+ rename_ctl(codec, "Capture Switch",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Switch" :
+ "Front-Panel Capture Switch");
+ break;
+ }
+}
+
static const struct hda_fixup alc882_fixups[] = {
[ALC882_FIXUP_ABIT_AW9D_MAX] = {
.type = HDA_FIXUP_PINS,
@@ -2198,6 +2254,10 @@ static const struct hda_fixup alc882_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_bass_chmap,
},
+ [ALC1220_FIXUP_GB_DUAL_CODECS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc1220_fixup_gb_dual_codecs,
+ },
};
static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -2267,6 +2327,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
@@ -4663,7 +4724,6 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
{ 0x1b, 0x21114000 }, /* dock speaker pin */
{}
};
- struct snd_kcontrol *kctl;
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
@@ -4678,12 +4738,10 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
/* this is a bit tricky; give more sane names for the main
* (tablet) speaker and the dock speaker, respectively
*/
- kctl = snd_hda_find_mixer_ctl(codec, "Speaker Playback Switch");
- if (kctl)
- strcpy(kctl->id.name, "Dock Speaker Playback Switch");
- kctl = snd_hda_find_mixer_ctl(codec, "Bass Speaker Playback Switch");
- if (kctl)
- strcpy(kctl->id.name, "Speaker Playback Switch");
+ rename_ctl(codec, "Speaker Playback Switch",
+ "Dock Speaker Playback Switch");
+ rename_ctl(codec, "Bass Speaker Playback Switch",
+ "Speaker Playback Switch");
break;
}
}
@@ -4766,6 +4824,30 @@ static void alc280_fixup_hp_9480m(struct hda_codec *codec,
}
}
+static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ alc_fixup_dual_codecs(codec, fix, action);
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /* override card longname to provide a unique UCM profile */
+ strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs");
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ /* rename Capture controls depending on the codec */
+ rename_ctl(codec, "Capture Volume",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Volume" :
+ "Front-Panel Capture Volume");
+ rename_ctl(codec, "Capture Switch",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Switch" :
+ "Front-Panel Capture Switch");
+ break;
+ }
+}
+
/* for hda_fixup_thinkpad_acpi() */
#include "thinkpad_helper.c"
@@ -4833,6 +4915,8 @@ enum {
ALC290_FIXUP_SUBWOOFER_HSJACK,
ALC269_FIXUP_THINKPAD_ACPI,
ALC269_FIXUP_DMIC_THINKPAD_ACPI,
+ ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+ ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
ALC255_FIXUP_HEADSET_MODE,
@@ -4872,6 +4956,12 @@ enum {
ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
ALC269_FIXUP_ATIV_BOOK_8,
ALC221_FIXUP_HP_MIC_NO_PRESENCE,
+ ALC256_FIXUP_ASUS_HEADSET_MODE,
+ ALC256_FIXUP_ASUS_MIC,
+ ALC256_FIXUP_ASUS_AIO_GPIO2,
+ ALC233_FIXUP_ASUS_MIC_NO_PRESENCE,
+ ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE,
+ ALC233_FIXUP_LENOVO_MULTI_CODECS,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -5289,6 +5379,24 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_THINKPAD_ACPI,
},
+ [ALC255_FIXUP_ACER_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC255_FIXUP_HEADSET_MODE
+ },
+ [ALC255_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC255_FIXUP_HEADSET_MODE
+ },
[ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -5579,6 +5687,54 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE
},
+ [ALC256_FIXUP_ASUS_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mode,
+ },
+ [ALC256_FIXUP_ASUS_MIC] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x13, 0x90a60160 }, /* use as internal mic */
+ { 0x19, 0x04a11120 }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
+ },
+ [ALC256_FIXUP_ASUS_AIO_GPIO2] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* Set up GPIO2 for the speaker amp */
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
+ { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 },
+ {}
+ },
+ },
+ [ALC233_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_HEADSET_MIC
+ },
+ [ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* Enables internal speaker */
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x40},
+ {0x20, AC_VERB_SET_PROC_COEF, 0x8800},
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE
+ },
+ [ALC233_FIXUP_LENOVO_MULTI_CODECS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5692,15 +5848,27 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC),
SND_PCI_QUIRK(0x103c, 0x82bf, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x82c0, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
@@ -5721,6 +5889,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
@@ -5875,6 +6044,18 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{0x21, 0x03211020}
static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1025, "Acer", ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+ {0x12, 0x90a601c0},
+ {0x14, 0x90171120},
+ {0x21, 0x02211030}),
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
+ {0x14, 0x90170110},
+ {0x1b, 0x90a70130},
+ {0x21, 0x03211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
+ {0x1a, 0x90a70130},
+ {0x1b, 0x90170110},
+ {0x21, 0x03211020}),
SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC225_STANDARD_PINS,
{0x12, 0xb7a60130},
@@ -5995,6 +6176,14 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x21, 0x02211020}),
SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC256_STANDARD_PINS),
+ SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC,
+ {0x14, 0x90170110},
+ {0x1b, 0x90a70130},
+ {0x21, 0x04211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC,
+ {0x14, 0x90170110},
+ {0x1b, 0x90a70130},
+ {0x21, 0x03211020}),
SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
{0x12, 0x90a60130},
{0x14, 0x90170110},
@@ -6714,6 +6903,7 @@ enum {
ALC668_FIXUP_DELL_DISABLE_AAMIX,
ALC668_FIXUP_DELL_XPS13,
ALC662_FIXUP_ASUS_Nx50,
+ ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
ALC668_FIXUP_ASUS_Nx51,
ALC891_FIXUP_HEADSET_MODE,
ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
@@ -6721,6 +6911,7 @@ enum {
ALC892_FIXUP_ASROCK_MOBO,
ALC662_FIXUP_USI_FUNC,
ALC662_FIXUP_USI_HEADSET_MODE,
+ ALC662_FIXUP_LENOVO_MULTI_CODECS,
};
static const struct hda_fixup alc662_fixups[] = {
@@ -6967,14 +7158,21 @@ static const struct hda_fixup alc662_fixups[] = {
.chained = true,
.chain_id = ALC662_FIXUP_BASS_1A
},
+ [ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mode_alc668,
+ .chain_id = ALC662_FIXUP_BASS_CHMAP
+ },
[ALC668_FIXUP_ASUS_Nx51] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
- {0x1a, 0x90170151}, /* bass speaker */
+ { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+ { 0x1a, 0x90170151 }, /* bass speaker */
+ { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
{}
},
.chained = true,
- .chain_id = ALC662_FIXUP_BASS_CHMAP,
+ .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
},
[ALC891_FIXUP_HEADSET_MODE] = {
.type = HDA_FIXUP_FUNC,
@@ -7019,6 +7217,10 @@ static const struct hda_fixup alc662_fixups[] = {
.chained = true,
.chain_id = ALC662_FIXUP_USI_FUNC
},
+ [ALC662_FIXUP_LENOVO_MULTI_CODECS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
+ },
};
static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -7056,6 +7258,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
+ SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),