ALSA: HDA: Enable SKU quirks for Realtek

Realtek have ways of specifying external amps and more via a
special nid or via the Codec's subsystem ID, this is called "SKU".
The computer manufacturer sometimes gets this wrong, so we need
to be able to override or ignore the SKU customization value.

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index c41ac30..7b24a2d 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -301,6 +301,7 @@
 	unsigned int  platform_type:1;
 	unsigned int  swap:1;
 	unsigned int  override:1;
+	unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
 };
 
 struct alc_spec {
@@ -1464,6 +1465,11 @@
 	spec->unsol_event = alc_sku_unsol_event;
 }
 
+/* Could be any non-zero and even value. When used as fixup, tells
+ * the driver to ignore any present sku defines.
+ */
+#define ALC_FIXUP_SKU_IGNORE (2)
+
 static int alc_auto_parse_customize_define(struct hda_codec *codec)
 {
 	unsigned int ass, tmp, i;
@@ -1472,6 +1478,13 @@
 
 	spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
 
+	if (spec->cdefine.fixup) {
+		ass = spec->cdefine.sku_cfg;
+		if (ass == ALC_FIXUP_SKU_IGNORE)
+			return -1;
+		goto do_sku;
+	}
+
 	ass = codec->subsystem_id & 0xffff;
 	if (ass != codec->bus->pci->subsystem_device && (ass & 1))
 		goto do_sku;
@@ -1539,6 +1552,13 @@
 	unsigned nid;
 	struct alc_spec *spec = codec->spec;
 
+	if (spec->cdefine.fixup) {
+		ass = spec->cdefine.sku_cfg;
+		if (ass == ALC_FIXUP_SKU_IGNORE)
+			return 0;
+		goto do_sku;
+	}
+
 	ass = codec->subsystem_id & 0xffff;
 	if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
 		goto do_sku;
@@ -1658,6 +1678,7 @@
 };
 
 struct alc_fixup {
+	unsigned int sku;
 	const struct alc_pincfg *pins;
 	const struct hda_verb *verbs;
 };
@@ -1668,12 +1689,22 @@
 			   int pre_init)
 {
 	const struct alc_pincfg *cfg;
+	struct alc_spec *spec;
 
 	quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
 	if (!quirk)
 		return;
 	fix += quirk->value;
 	cfg = fix->pins;
+	if (pre_init && fix->sku) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+		snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n",
+			    codec->chip_name, quirk->name);
+#endif
+		spec = codec->spec;
+		spec->cdefine.sku_cfg = fix->sku;
+		spec->cdefine.fixup = 1;
+	}
 	if (pre_init && cfg) {
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 		snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
@@ -10861,8 +10892,6 @@
 
 	codec->spec = spec;
 
-	alc_auto_parse_customize_define(codec);
-
 	switch (codec->vendor_id) {
 	case 0x10ec0882:
 	case 0x10ec0885:
@@ -10890,6 +10919,8 @@
 	if (board_config == ALC882_AUTO)
 		alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
 
+	alc_auto_parse_customize_define(codec);
+
 	if (board_config == ALC882_AUTO) {
 		/* automatic parse from the BIOS config */
 		err = alc882_parse_auto_config(codec);