Enhance/fix some aspects related to STAC92HD71Bx and STAC92HD75Bx support:
* Split STAC92HD71B* support from one model to three models (4 port, 5 port,
  6 port), because of different number of default pins. May be trying to change
  stac92xx_set_config_regs to check for pin_nids set to 0 for example would be
  better (and requiring to check anything else that uses pin_nids array),
  instead of splitting models just because of different number of pins
  supported.
* Add additional init verbs for all STAC92HD71Bx and STAC92HD75Bx models to
  ensure widgets are properly connected and configured, and also remove invalid
  reference to 0xf pin for model without analog mixer (don't have the pin).
* Removed analog loopback mixer items, not mentioned in sigmatel datasheets and
  reported to break sound support.
* Add support to stac92xx_set_config_regs to skip write to pin cfg if pin cfg
  array item is zero.
* Add new stac92hd71bxx hp-m* models, with pci quirks for known machines, pin
  cfgs sources comes from *.ini files from sigmatel windows drivers provided by
  HP.
* Detect dynamically looking at pin configs the number of connected ports and
  number of smuxes using new introduced functions stac92hd71bxx_connected_ports
  and stac92hd71bxx_connected_smuxes.
* Use proper input mux configuration for 4port and 5port models.
* Set eapd_mask and eapd_switch, looks to be required.
* Remove pwr_nids/num_pwrs>0 etc. setting for all STAC92HD71Bx and STAC92HD75Bx
  models, datasheets shows no power management support on any pins. Also
  stac92xx_parse_auto_config was using uneeded/wrong third parameter = 0x23.

Signed-off-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br>

---
 Documentation/sound/alsa/ALSA-Configuration.txt |   14
 sound/pci/hda/patch_sigmatel.c                  |  620 +++++++++++++++++++-----
 2 files changed, 516 insertions(+), 118 deletions(-)

diff -p -up linux-2.6.28/Documentation/sound/alsa/ALSA-Configuration.txt.orig linux-2.6.28/Documentation/sound/alsa/ALSA-Configuration.txt
--- linux-2.6.28/Documentation/sound/alsa/ALSA-Configuration.txt.orig	2009-01-28 07:38:38.000000000 -0500
+++ linux-2.6.28/Documentation/sound/alsa/ALSA-Configuration.txt	2009-01-28 07:40:30.000000000 -0500
@@ -1070,11 +1070,23 @@ Prior to version 0.9.0rc4 options had a 
 	  dell-3stack	Dell Dimension E520
 	  dell-bios	Fixes with Dell BIOS setup
 
-	STAC92HD71B*
+	STAC92HD71B5 (4 port)
+	  ref		Reference board
+
+	STAC92HD75B[12] (5 port)
+	  ref		Reference board
+	  hp-m4		HP laptops
+
+	STAC92HD71B[678]/STAC92HD75B[34] (6 port)
 	  ref		Reference board
 	  dell-m4-1	Dell desktops
 	  dell-m4-2	Dell desktops
 	  dell-m4-3	Dell desktops
+	  hp-m4-1	HP laptops
+	  hp-m4-2	HP laptops
+	  hp-m4-3	HP laptops
+	  hp-m4-4	HP laptops
+	  hp-m4-5	HP laptops
 
 	STAC92HD73*
 	  ref		Reference board
diff -p -up linux-2.6.28/sound/pci/hda/patch_sigmatel.c.orig linux-2.6.28/sound/pci/hda/patch_sigmatel.c
--- linux-2.6.28/sound/pci/hda/patch_sigmatel.c.orig	2009-01-28 07:39:54.000000000 -0500
+++ linux-2.6.28/sound/pci/hda/patch_sigmatel.c	2009-01-28 07:40:30.000000000 -0500
@@ -84,12 +84,26 @@ enum {
 };
 
 enum {
+	STAC_92HD71B5_REF,
+	STAC_92HD71B5_MODELS
+};
+
+enum {
+	STAC_92HD75B_5PORT_REF,
+	STAC_HP_M4,
+	STAC_92HD75B_5PORT_MODELS
+};
+
+enum {
 	STAC_92HD71BXX_REF,
 	STAC_DELL_M4_1,
 	STAC_DELL_M4_2,
 	STAC_DELL_M4_3,
-	STAC_HP_M4,
-	STAC_HP_DV5,
+	STAC_HP_M4_1,
+	STAC_HP_M4_2,
+	STAC_HP_M4_3,
+	STAC_HP_M4_4,
+	STAC_HP_M4_5,
 	STAC_92HD71BXX_MODELS
 };
 
@@ -320,10 +334,6 @@ static unsigned int stac92hd83xxx_pwr_ma
 	0x03, 0x0c, 0x10, 0x40,
 };
 
-static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
-	0x0a, 0x0d, 0x0f
-};
-
 static hda_nid_t stac92hd71bxx_adc_nids[2] = {
 	0x12, 0x13,
 };
@@ -344,6 +354,11 @@ static hda_nid_t stac92hd71bxx_dac_nids[
 	0x10, /*0x11, */
 };
 
+#define STAC92HD75B_5PORT_NUM_DMICS 1
+static hda_nid_t stac92hd75b_5port_dmic_nids[STAC92HD75B_5PORT_NUM_DMICS + 1] = {
+	0x18, 0
+};
+
 #define STAC92HD71BXX_NUM_DMICS	2
 static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
 	0x18, 0x19, 0
@@ -459,10 +474,22 @@ static hda_nid_t stac92hd83xxx_pin_nids[
 	0x0f, 0x10, 0x11, 0x12, 0x13,
 	0x1d, 0x1e, 0x1f, 0x20
 };
-static hda_nid_t stac92hd71bxx_pin_nids[11] = {
+
+static hda_nid_t stac92hd71b5_pin_nids[11] = {
+	0x0a, 0x0b, 0x0c, 0x0d, 0x14,
+	0x18, 0x19, 0x1e, 0x1f, 0x20,
+	0x27
+};
+
+static hda_nid_t stac92hd75b_5port_pin_nids[10] = {
+	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+	0x14, 0x18, 0x1e, 0x1f, 0x20
+};
+
+static hda_nid_t stac92hd71bxx_pin_nids[13] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x14, 0x18, 0x19, 0x1e,
-	0x1f,
+	0x1f, 0x20, 0x27
 };
 
 static hda_nid_t stac927x_pin_nids[14] = {
@@ -868,10 +895,15 @@ static struct hda_verb stac92hd71bxx_cor
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* connect headphone jack to dac1 */
 	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-	/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
+	/* connect port D/mono out to dac0 */
+	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ 0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* make sure dmuxes are initially connected to analog muxes */
+	{ 0x1c, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ 0x1d, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* unmute right and left channels for nodes 0x0a, 0xd */
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{}
 };
 
@@ -889,6 +921,12 @@ static struct hda_verb stac92hd71bxx_ana
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* connect headphone jack to dac1 */
 	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	/* connect port D/mono out to dac0 */
+	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ 0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* unmute and max step for dac0/dac1 inputs in mixer */
+	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
+	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x711f},
 	/* unmute right and left channels for nodes 0x0a, 0xd */
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1109,7 +1147,6 @@ static struct snd_kcontrol_new stac92hd8
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
 	STAC_INPUT_SOURCE(2),
-	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1138,7 +1175,6 @@ static struct snd_kcontrol_new stac92hd7
 
 static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
 	STAC_INPUT_SOURCE(2),
-	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1673,28 +1709,107 @@ static struct snd_pci_quirk stac92hd83xx
 	{} /* terminator */
 };
 
-static unsigned int ref92hd71bxx_pin_configs[11] = {
+static unsigned int ref92hd71b5_pin_configs[] = {
+	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
+	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x01452050,
+	0x98560060, 0x40f000f0, 0x40f000f0,
+};
+
+static unsigned int *stac92hd71b5_brd_tbl[STAC_92HD71B5_MODELS] = {
+	[STAC_92HD71B5_REF] = ref92hd71b5_pin_configs,
+};
+
+static const char *stac92hd71b5_models[STAC_92HD71B5_MODELS] = {
+	[STAC_92HD71B5_REF] = "ref",
+};
+
+static struct snd_pci_quirk stac92hd71b5_cfg_tbl[] = {
+	{} /* terminator */
+};
+
+static unsigned int ref92hd75b_5port_pin_configs[] = {
+	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
+	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x01452050,
+	0x98560060, 0x40f000f0,
+};
+
+static unsigned int *stac92hd75b_5port_brd_tbl[STAC_92HD75B_5PORT_MODELS] = {
+	[STAC_92HD75B_5PORT_REF]	= ref92hd75b_5port_pin_configs,
+	[STAC_HP_M4]			= NULL,
+};
+
+static const char *stac92hd75b_5port_models[STAC_92HD75B_5PORT_MODELS] = {
+	[STAC_92HD75B_5PORT_REF] = "ref",
+	[STAC_HP_M4]		 = "hp-m4",
+};
+
+static struct snd_pci_quirk stac92hd75b_5port_cfg_tbl[] = {
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
+				"unknown HP", STAC_HP_M4),
+	{} /* terminator */
+};
+
+static unsigned int ref92hd71bxx_pin_configs[13] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
 	0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
-	0x90a000f0, 0x01452050, 0x01452050,
+	0x90a000f0, 0x01452050, 0x01452050, 0x00000000,
+	0x00000000,
 };
 
-static unsigned int dell_m4_1_pin_configs[11] = {
+static unsigned int dell_m4_1_pin_configs[13] = {
 	0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
-	0x40f000f0, 0x4f0000f0, 0x4f0000f0,
+	0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000,
+	0x00000000,
 };
 
-static unsigned int dell_m4_2_pin_configs[11] = {
+static unsigned int dell_m4_2_pin_configs[13] = {
 	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
-	0x40f000f0, 0x044413b0, 0x044413b0,
+	0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
+	0x00000000,
 };
 
-static unsigned int dell_m4_3_pin_configs[11] = {
+static unsigned int dell_m4_3_pin_configs[13] = {
 	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
 	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
-	0x40f000f0, 0x044413b0, 0x044413b0,
+	0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
+	0x00000000,
+};
+
+static unsigned int hp_m4_1_pin_configs[13] = {
+	0x0221201f, 0x02a12050, 0x40f000f0, 0x90170010,
+	0x40f000f1, 0x0221201f, 0x40f000f2, 0x90a60040,
+	0x50f000f3, 0x28466060, 0x50f000f4, 0x00000000,
+	0x90300041,
+};
+
+static unsigned int hp_m4_2_pin_configs[13] = {
+	0x0221201f, 0x02a1205e, 0x40f000f1, 0x90170010,
+	0x4080005f, 0x40f000f5, 0x40f000f2, 0x90a60070,
+	0x50f000f3, 0x50f000f4, 0x50f000f5, 0x28466060,
+	0x9030005a,
+};
+
+static unsigned int hp_m4_3_pin_configs[13] = {
+	0x0221201f, 0x02a1205e, 0x40f000f1, 0x90170010,
+	0x4080005f, 0x40f000f5, 0x40f000f2, 0x90a60070,
+	0x50f000f3, 0x28466060, 0x50f000f4, 0x40f000f0,
+	0x9030005a,
+};
+
+static unsigned int hp_m4_4_pin_configs[13] = {
+	0x0221201f, 0x02a12050, 0x90a70040, 0x90170010,
+	0x40f000f1, 0x40f000f5, 0x40f000f2, 0x50f000f6,
+	0x50f000f3, 0x50f000f7, 0x50f000f4, 0x28466060,
+	0x9030005a,
+};
+
+static unsigned int hp_m4_5_pin_configs[13] = {
+	0x0221201f, 0x02a1205e, 0x90a70070, 0x90170010,
+	0x4080005f, 0x40f000f5, 0x40f000f2, 0x50f000f1,
+	0x50f000f3, 0x50f000f6, 0x50f000f4, 0x28466060,
+	0x9030005a,
 };
 
 static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
@@ -1702,8 +1817,11 @@ static unsigned int *stac92hd71bxx_brd_t
 	[STAC_DELL_M4_1]	= dell_m4_1_pin_configs,
 	[STAC_DELL_M4_2]	= dell_m4_2_pin_configs,
 	[STAC_DELL_M4_3]	= dell_m4_3_pin_configs,
-	[STAC_HP_M4]		= NULL,
-	[STAC_HP_DV5]		= NULL,
+	[STAC_HP_M4_1]		= hp_m4_1_pin_configs,
+	[STAC_HP_M4_2]		= hp_m4_2_pin_configs,
+	[STAC_HP_M4_3]		= hp_m4_3_pin_configs,
+	[STAC_HP_M4_4]		= hp_m4_4_pin_configs,
+	[STAC_HP_M4_5]		= hp_m4_5_pin_configs,
 };
 
 static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
@@ -1711,24 +1829,59 @@ static const char *stac92hd71bxx_models[
 	[STAC_DELL_M4_1] = "dell-m4-1",
 	[STAC_DELL_M4_2] = "dell-m4-2",
 	[STAC_DELL_M4_3] = "dell-m4-3",
-	[STAC_HP_M4] = "hp-m4",
-	[STAC_HP_DV5] = "hp-dv5",
+	[STAC_HP_M4_1] = "hp-m4-1",
+	[STAC_HP_M4_2] = "hp-m4-2",
+	[STAC_HP_M4_3] = "hp-m4-3",
+	[STAC_HP_M4_4] = "hp-m4-4",
+	[STAC_HP_M4_5] = "hp-m4-5",
 };
 
 static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_92HD71BXX_REF),
-	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
-		      "HP dv5", STAC_HP_M4),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30de,
+		      "unknown HP", STAC_HP_M4_1),
+	SND_PCI_QUIRK(0x30de, 0x103c,
+		      "unknown HP", STAC_HP_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1505,
+		      "unknown HP", STAC_HP_M4_1),
+	SND_PCI_QUIRK(0x1505, 0x103c,
+		      "unknown HP", STAC_HP_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f3,
+		      "unknown HP", STAC_HP_M4_2),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
-		      "HP dv7", STAC_HP_M4),
+		      "HP dv7", STAC_HP_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f7,
+		      "unknown HP", STAC_HP_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb,
+		      "unknown HP", STAC_HP_M4_2),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
-		      "HP dv7", STAC_HP_M4),
+		      "unknown HP", STAC_HP_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fd,
+		      "unknown HP", STAC_HP_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
+		      "HP dv5", STAC_HP_M4_3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3600,
+		      "unknown HP", STAC_HP_M4_3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3602,
+		      "unknown HP", STAC_HP_M4_3),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603,
-		      "HP dv5", STAC_HP_DV5),
-	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
-				"unknown HP", STAC_HP_M4),
+		      "unknown HP", STAC_HP_M4_3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x360f,
+		      "unknown HP", STAC_HP_M4_3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3610,
+		      "unknown HP", STAC_HP_M4_3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30ff,
+		      "unknown HP", STAC_HP_M4_4),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3601,
+		      "unknown HP", STAC_HP_M4_4),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3607,
+		      "unknown HP", STAC_HP_M4_4),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f8,
+		      "unknown HP", STAC_HP_M4_5),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fe,
+		      "unknown HP", STAC_HP_M4_5),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
 				"unknown Dell", STAC_DELL_M4_1),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
@@ -2262,9 +2415,11 @@ static void stac92xx_set_config_regs(str
  	if (!spec->pin_configs)
  		return;
 
-	for (i = 0; i < spec->num_pins; i++)
-		stac92xx_set_config_reg(codec, spec->pin_nids[i],
-					spec->pin_configs[i]);
+	for (i = 0; i < spec->num_pins; i++) {
+		if (spec->pin_configs[i])
+			stac92xx_set_config_reg(codec, spec->pin_nids[i],
+						spec->pin_configs[i]);
+	}
 }
 
 /*
@@ -4527,6 +4682,282 @@ static struct hda_codec_ops stac92hd71bx
 #endif
 };
 
+static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
+					 hda_nid_t *nids, int num_nids)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int idx, num;
+	unsigned int def_conf;
+
+	for (num = 0; num < num_nids; num++) {
+		for (idx = 0; idx < spec->num_pins; idx++)
+			if (spec->pin_nids[idx] == nids[num])
+				break;
+		if (idx >= spec->num_pins)
+			break;
+		def_conf = get_defcfg_connect(spec->pin_configs[idx]);
+		if (def_conf == AC_JACK_PORT_NONE) 
+			break;
+	}
+	return num;
+}
+
+static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
+					  hda_nid_t dig0pin)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int idx;
+
+	for (idx = 0; idx < spec->num_pins; idx++)
+		if (spec->pin_nids[idx] == dig0pin)
+			break;
+	if ((idx + 2) >= spec->num_pins)
+		return 0;
+
+	/* dig1pin case */
+	if (get_defcfg_connect(spec->pin_configs[idx+1]) != AC_JACK_PORT_NONE)
+		return 2;
+
+	/* dig0pin + dig2pin case */
+	if (get_defcfg_connect(spec->pin_configs[idx+2]) != AC_JACK_PORT_NONE)
+		return 2;
+	if (get_defcfg_connect(spec->pin_configs[idx]) != AC_JACK_PORT_NONE)
+		return 1;
+	else
+		return 0;
+}
+
+static struct hda_input_mux stac92hd71b5_dmux = {
+	.num_items = 3,
+	.items = {
+		{ "Analog Inputs", 0x00 },
+		{ "Digital Mic 1", 0x02 },
+		{ "Digital Mic 2", 0x03 },
+	}
+};
+
+static int patch_stac92hd71b5(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec;
+	int err = 0;
+
+	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+	codec->patch_ops = stac92xx_patch_ops;
+	spec->num_pins = ARRAY_SIZE(stac92hd71b5_pin_nids);
+	spec->pin_nids = stac92hd71b5_pin_nids;
+
+	memcpy(&spec->private_dimux, &stac92hd71b5_dmux,
+			sizeof(stac92hd71b5_dmux));
+	spec->board_config = snd_hda_check_board_config(codec,
+							STAC_92HD71B5_MODELS,
+							stac92hd71b5_models,
+							stac92hd71b5_cfg_tbl);
+again:
+	if (spec->board_config < 0) {
+		snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+			" STAC92HD71B5, using BIOS defaults\n");
+		err = stac92xx_save_bios_config_regs(codec);
+		if (err < 0) {
+			stac92xx_free(codec);
+			return err;
+		}
+		spec->pin_configs = spec->bios_pin_configs;
+	} else {
+		spec->pin_configs = stac92hd71b5_brd_tbl[spec->board_config];
+		stac92xx_set_config_regs(codec);
+	}
+
+	if (spec->board_config > STAC_92HD71B5_REF) {
+		/* GPIO0 = EAPD */
+		spec->gpio_mask = 0x01;
+		spec->gpio_dir = 0x01;
+		spec->gpio_data = 0x01;
+		spec->eapd_mask = 0x01; /* needed? */
+		spec->eapd_switch = 1;  /* needed? */
+	}
+
+	spec->mixer = stac92hd71bxx_mixer;
+	spec->init = stac92hd71bxx_core_init;
+	codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
+
+	spec->num_pwrs = 0;
+	spec->powerdown_adcs = 1;
+	spec->digbeep_nid = 0x26;
+
+	spec->mux_nids = stac92hd71bxx_mux_nids;
+	spec->adc_nids = stac92hd71bxx_adc_nids;
+	spec->dmic_nids = stac92hd71bxx_dmic_nids;
+	spec->dmux_nids = stac92hd71bxx_dmux_nids;
+	spec->smux_nids = stac92hd71bxx_smux_nids;
+	spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
+	spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
+	spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+				stac92hd71bxx_dmic_nids,
+				STAC92HD71BXX_NUM_DMICS);
+	if (spec->num_dmics) {
+		spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+		spec->dinput_mux = &spec->private_dimux;
+		spec->private_dimux.num_items += spec->num_dmics -
+			(ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
+	}
+	spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
+
+	spec->multiout.num_dacs = 1;
+	spec->multiout.hp_nid = 0x11;
+	spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+
+	err = stac92xx_parse_auto_config(codec, 0x21, 0);
+	if (!err) {
+		if (spec->board_config < 0) {
+			printk(KERN_WARNING "hda_codec: No auto-config is "
+			       "available, default to model=ref\n");
+			spec->board_config = STAC_92HD71B5_REF;
+			goto again;
+		}
+		err = -EINVAL;
+	}
+
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
+	}
+
+	return 0;
+}
+
+static struct hda_input_mux stac92hd75b_5port_dmux = {
+	.num_items = 3,
+	.items = {
+		{ "Analog Inputs", 0x00 },
+		{ "Mixer", 0x01 },
+		{ "Digital Mic 1", 0x02 },
+	}
+};
+
+static int patch_stac92hd75b_5port(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec;
+	int err = 0;
+
+	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+	codec->patch_ops = stac92xx_patch_ops;
+	spec->num_pins = ARRAY_SIZE(stac92hd75b_5port_pin_nids);
+	spec->pin_nids = stac92hd75b_5port_pin_nids;
+
+	memcpy(&spec->private_dimux, &stac92hd75b_5port_dmux,
+			sizeof(stac92hd75b_5port_dmux));
+	spec->board_config = snd_hda_check_board_config(codec,
+							STAC_92HD75B_5PORT_MODELS,
+							stac92hd75b_5port_models,
+							stac92hd75b_5port_cfg_tbl);
+again:
+	if (spec->board_config < 0) {
+		snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+			" STAC92HD75B_5PORT, using BIOS defaults\n");
+		err = stac92xx_save_bios_config_regs(codec);
+		if (err < 0) {
+			stac92xx_free(codec);
+			return err;
+		}
+		spec->pin_configs = spec->bios_pin_configs;
+	} else {
+		spec->pin_configs = stac92hd75b_5port_brd_tbl[spec->board_config];
+		if (!spec->pin_configs) {
+			err = stac92xx_save_bios_config_regs(codec);
+			if (err < 0) {
+				stac92xx_free(codec);
+				return err;
+			}
+			spec->pin_configs = spec->bios_pin_configs;
+		} else
+			stac92xx_set_config_regs(codec);
+	}
+
+	if (spec->board_config > STAC_92HD75B_5PORT_REF) {
+		/* GPIO0 = EAPD */
+		spec->gpio_mask = 0x01;
+		spec->gpio_dir = 0x01;
+		spec->gpio_data = 0x01;
+		spec->eapd_mask = 0x01; /* needed? */
+		spec->eapd_switch = 1;  /* needed? */
+	}
+
+	if (spec->board_config == STAC_HP_M4) {
+		/* Enable VREF power saving on GPIO1 detect */
+		snd_hda_codec_write_cache(codec, codec->afg, 0,
+			AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
+		snd_hda_codec_write_cache(codec, codec->afg, 0,
+				AC_VERB_SET_UNSOLICITED_ENABLE,
+				(AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
+		spec->gpio_mask |= 0x02;
+		stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
+					stac92xx_auto_set_pinctl(codec, 0x0e,
+					AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
+		spec->pin_configs[4] = 0x01813040;
+	}
+	if ((codec->revision_id & 0xf) == 0 ||
+			(codec->revision_id & 0xf) == 1) {
+#ifdef SND_HDA_NEEDS_RESUME
+		codec->patch_ops = stac92hd71bxx_patch_ops;
+#endif
+		spec->stream_delay = 40; /* 40 milliseconds */
+	}
+
+	spec->mixer = stac92hd71bxx_analog_mixer;
+	spec->dinput_mux = &spec->private_dimux;
+	spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
+	codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
+
+	spec->num_pwrs = 0;
+	spec->powerdown_adcs = 1;
+	spec->digbeep_nid = 0x26;
+
+	spec->mux_nids = stac92hd71bxx_mux_nids;
+	spec->adc_nids = stac92hd71bxx_adc_nids;
+	spec->dmic_nids = stac92hd75b_5port_dmic_nids;
+	spec->dmux_nids = stac92hd71bxx_dmux_nids;
+	spec->smux_nids = stac92hd71bxx_smux_nids;
+	spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
+	spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
+	spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+				stac92hd75b_5port_dmic_nids,
+				STAC92HD75B_5PORT_NUM_DMICS);
+	spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+	spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
+
+	spec->multiout.num_dacs = 1;
+	spec->multiout.hp_nid = 0x11;
+	spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+	spec->private_dimux.num_items += spec->num_dmics -
+		(ARRAY_SIZE(stac92hd75b_5port_dmic_nids) - 1);
+
+	err = stac92xx_parse_auto_config(codec, 0x21, 0);
+	if (!err) {
+		if (spec->board_config < 0) {
+			printk(KERN_WARNING "hda_codec: No auto-config is "
+			       "available, default to model=ref\n");
+			spec->board_config = STAC_92HD75B_5PORT_REF;
+			goto again;
+		}
+		err = -EINVAL;
+	}
+
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
+	}
+
+	return 0;
+}
+
 static struct hda_input_mux stac92hd71bxx_dmux = {
 	.num_items = 4,
 	.items = {
@@ -4549,10 +4980,12 @@ static int patch_stac92hd71bxx(struct hd
 	codec->spec = spec;
 	codec->patch_ops = stac92xx_patch_ops;
 	spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
-	spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
 	spec->pin_nids = stac92hd71bxx_pin_nids;
-	memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
-			sizeof(stac92hd71bxx_dmux));
+
+	/* On 92HD75B3/92HD75B4 0x27 isn't a pin nid */
+	if (codec->vendor_id == 0x111d7603)
+		spec->num_pins--;
+
 	spec->board_config = snd_hda_check_board_config(codec,
 							STAC_92HD71BXX_MODELS,
 							stac92hd71bxx_models,
@@ -4577,46 +5010,35 @@ again:
 		spec->gpio_mask = 0x01;
 		spec->gpio_dir = 0x01;
 		spec->gpio_data = 0x01;
+		spec->eapd_mask = 0x01; /* needed? */
+		spec->eapd_switch = 1;  /* needed? */
 	}
 
+	spec->mux_nids = stac92hd71bxx_mux_nids;
+	spec->adc_nids = stac92hd71bxx_adc_nids;
+	spec->dmic_nids = stac92hd71bxx_dmic_nids;
+	spec->dmux_nids = stac92hd71bxx_dmux_nids;
+	spec->smux_nids = stac92hd71bxx_smux_nids;
+	spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
+	spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
+	spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+				stac92hd71bxx_dmic_nids,
+				STAC92HD71BXX_NUM_DMICS);
+	spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
+
 	switch (codec->vendor_id) {
-	case 0x111d76b6: /* 4 Port without Analog Mixer */
-	case 0x111d76b7:
 	case 0x111d76b4: /* 6 Port without Analog Mixer */
 	case 0x111d76b5:
+		memcpy(&spec->private_dimux, &stac92hd71b5_dmux,
+			sizeof(stac92hd71b5_dmux));
+		if (spec->num_dmics) {
+			spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+			spec->dinput_mux = &spec->private_dimux;
+		}
 		spec->mixer = stac92hd71bxx_mixer;
 		spec->init = stac92hd71bxx_core_init;
 		codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
 		break;
-	case 0x111d7608: /* 5 Port with Analog Mixer */
-		switch (spec->board_config) {
-		case STAC_HP_M4:
-			/* Enable VREF power saving on GPIO1 detect */
-			snd_hda_codec_write_cache(codec, codec->afg, 0,
-				AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
-			snd_hda_codec_write_cache(codec, codec->afg, 0,
-					AC_VERB_SET_UNSOLICITED_ENABLE,
-					(AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
-			spec->gpio_mask |= 0x02;
-			break;
-		}
-		if ((codec->revision_id & 0xf) == 0 ||
-				(codec->revision_id & 0xf) == 1) {
-#ifdef SND_HDA_NEEDS_RESUME
-			codec->patch_ops = stac92hd71bxx_patch_ops;
-#endif
-			spec->stream_delay = 40; /* 40 milliseconds */
-		}
-
-		/* no output amps */
-		spec->num_pwrs = 0;
-		spec->mixer = stac92hd71bxx_analog_mixer;
-		spec->dinput_mux = &spec->private_dimux;
-
-		/* disable VSW */
-		spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
-		stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
-		break;
 	case 0x111d7603: /* 6 Port with Analog Mixer */
 		if ((codec->revision_id & 0xf) == 1) {
 #ifdef SND_HDA_NEEDS_RESUME
@@ -4624,65 +5046,29 @@ again:
 #endif
 			spec->stream_delay = 40; /* 40 milliseconds */
 		}
-
-		/* no output amps */
-		spec->num_pwrs = 0;
 		/* fallthru */
 	default:
+		memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
+			sizeof(stac92hd71bxx_dmux));
 		spec->dinput_mux = &spec->private_dimux;
+		spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
 		spec->mixer = stac92hd71bxx_analog_mixer;
 		spec->init = stac92hd71bxx_analog_core_init;
 		codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
 	}
 
-	spec->aloopback_mask = 0x50;
-	spec->aloopback_shift = 0;
-
+	spec->num_pwrs = 0;
 	spec->powerdown_adcs = 1;
 	spec->digbeep_nid = 0x26;
-	spec->mux_nids = stac92hd71bxx_mux_nids;
-	spec->adc_nids = stac92hd71bxx_adc_nids;
-	spec->dmic_nids = stac92hd71bxx_dmic_nids;
-	spec->dmux_nids = stac92hd71bxx_dmux_nids;
-	spec->smux_nids = stac92hd71bxx_smux_nids;
-	spec->pwr_nids = stac92hd71bxx_pwr_nids;
-
-	spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
-	spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
-
-	switch (spec->board_config) {
-	case STAC_HP_M4:
-		/* enable internal microphone */
-		stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
-		stac92xx_auto_set_pinctl(codec, 0x0e,
-			AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
-		/* fallthru */
-	case STAC_DELL_M4_2:
-		spec->num_dmics = 0;
-		spec->num_smuxes = 0;
-		spec->num_dmuxes = 0;
-		break;
-	case STAC_DELL_M4_1:
-	case STAC_DELL_M4_3:
-		spec->num_dmics = 1;
-		spec->num_smuxes = 0;
-		spec->num_dmuxes = 0;
-		break;
-	default:
-		spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
-		spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
-		spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
-	};
 
 	spec->multiout.num_dacs = 1;
 	spec->multiout.hp_nid = 0x11;
 	spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
-	if (spec->dinput_mux)
-		spec->private_dimux.num_items +=
+	spec->private_dimux.num_items +=
 			spec->num_dmics -
 				(ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
 
-	err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
+	err = stac92xx_parse_auto_config(codec, 0x21, 0);
 	if (!err) {
 		if (spec->board_config < 0) {
 			printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -4699,7 +5085,7 @@ again:
 	}
 
 	return 0;
-};
+}
 
 static int patch_stac922x(struct hda_codec *codec)
 {
@@ -5335,10 +5721,10 @@ struct hda_codec_preset snd_hda_preset_s
  	{ .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
  	{ .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
  	{ .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
-	{ .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
-	{ .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
-	{ .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
-	{ .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
+	{ .id = 0x111d7603, .name = "92HD75B3/4", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx },
+	{ .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx },
+	{ .id = 0x111d7608, .name = "92HD75B1/2", .patch = patch_stac92hd75b_5port },
 	{ .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
 	{ .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
 	{ .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
@@ -5348,7 +5734,7 @@ struct hda_codec_preset snd_hda_preset_s
 	{ .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
 	{ .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
 	{ .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
-	{ .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
-	{ .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71b5 },
+	{ .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71b5 },
 	{} /* terminator */
 };
