Merge branch 'fix/hda' into topic/hda
[linux-2.6.git] / sound / pci / hda / patch_via.c
index 0997031..6a51ffb 100644 (file)
@@ -98,9 +98,15 @@ enum VIA_HDA_CODEC {
        VT1716S,
        VT2002P,
        VT1812,
+       VT1802,
        CODEC_TYPES,
 };
 
+#define VT2002P_COMPATIBLE(spec) \
+       ((spec)->codec_type == VT2002P ||\
+        (spec)->codec_type == VT1812 ||\
+        (spec)->codec_type == VT1802)
+
 struct via_spec {
        /* codec parameterization */
        struct snd_kcontrol_new *mixers[6];
@@ -154,6 +160,9 @@ struct via_spec {
        struct delayed_work vt1708_hp_work;
        int vt1708_jack_detectect;
        int vt1708_hp_present;
+
+       void (*set_widgets_power_state)(struct hda_codec *codec);
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
 #endif
@@ -218,17 +227,19 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
                codec_type = VT1812;
        else if (dev_id == 0x0440)
                codec_type = VT1708S;
+       else if ((dev_id & 0xfff) == 0x446)
+               codec_type = VT1802;
        else
                codec_type = UNKNOWN;
        return codec_type;
 };
 
+#define VIA_JACK_EVENT         0x20
 #define VIA_HP_EVENT           0x01
 #define VIA_GPIO_EVENT         0x02
-#define VIA_JACK_EVENT         0x04
-#define VIA_MONO_EVENT         0x08
-#define VIA_SPEAKER_EVENT      0x10
-#define VIA_BIND_HP_EVENT      0x20
+#define VIA_MONO_EVENT         0x03
+#define VIA_SPEAKER_EVENT      0x04
+#define VIA_BIND_HP_EVENT      0x05
 
 enum {
        VIA_CTL_WIDGET_VOL,
@@ -245,7 +256,6 @@ enum {
 };
 
 static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
-static void set_jack_power_state(struct hda_codec *codec);
 static int is_aa_path_mute(struct hda_codec *codec);
 
 static void vt1708_start_hp_work(struct via_spec *spec)
@@ -271,6 +281,12 @@ static void vt1708_stop_hp_work(struct via_spec *spec)
        cancel_delayed_work_sync(&spec->vt1708_hp_work);
 }
 
+static void set_widgets_power_state(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       if (spec->set_widgets_power_state)
+               spec->set_widgets_power_state(codec);
+}
 
 static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
@@ -278,7 +294,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
        int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 
-       set_jack_power_state(codec);
+       set_widgets_power_state(codec);
        analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
        if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
                if (is_aa_path_mute(codec))
@@ -602,482 +618,6 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
 }
 
-static void set_jack_power_state(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int imux_is_smixer;
-       unsigned int parm;
-
-       if (spec->codec_type == VT1702) {
-               imux_is_smixer = snd_hda_codec_read(
-                       codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-               /* inputs */
-               /* PW 1/2/5 (14h/15h/18h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x14, &parm);
-               set_pin_power_state(codec, 0x15, &parm);
-               set_pin_power_state(codec, 0x18, &parm);
-               if (imux_is_smixer)
-                       parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
-               /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
-               snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* outputs */
-               /* PW 3/4 (16h/17h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x16, &parm);
-               set_pin_power_state(codec, 0x17, &parm);
-               /* MW0 (1ah), AOW 0/1 (10h/1dh) */
-               snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
-                                   imux_is_smixer ? AC_PWRST_D0 : parm);
-               snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-       } else if (spec->codec_type == VT1708B_8CH
-                  || spec->codec_type == VT1708B_4CH
-                  || spec->codec_type == VT1708S) {
-               /* SW0 (17h) = stereo mixer */
-               int is_8ch = spec->codec_type != VT1708B_4CH;
-               imux_is_smixer = snd_hda_codec_read(
-                       codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
-                       == ((spec->codec_type == VT1708S)  ? 5 : 0);
-               /* inputs */
-               /* PW 1/2/5 (1ah/1bh/1eh) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x1a, &parm);
-               set_pin_power_state(codec, 0x1b, &parm);
-               set_pin_power_state(codec, 0x1e, &parm);
-               if (imux_is_smixer)
-                       parm = AC_PWRST_D0;
-               /* SW0 (17h), AIW 0/1 (13h/14h) */
-               snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* outputs */
-               /* PW0 (19h), SW1 (18h), AOW1 (11h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x19, &parm);
-               if (spec->smart51_enabled)
-                       parm = AC_PWRST_D0;
-               snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* PW6 (22h), SW2 (26h), AOW2 (24h) */
-               if (is_8ch) {
-                       parm = AC_PWRST_D3;
-                       set_pin_power_state(codec, 0x22, &parm);
-                       if (spec->smart51_enabled)
-                               parm = AC_PWRST_D0;
-                       snd_hda_codec_write(codec, 0x26, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-                       snd_hda_codec_write(codec, 0x24, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-               }
-
-               /* PW 3/4/7 (1ch/1dh/23h) */
-               parm = AC_PWRST_D3;
-               /* force to D0 for internal Speaker */
-               set_pin_power_state(codec, 0x1c, &parm);
-               set_pin_power_state(codec, 0x1d, &parm);
-               if (is_8ch)
-                       set_pin_power_state(codec, 0x23, &parm);
-               /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
-               snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
-                                   imux_is_smixer ? AC_PWRST_D0 : parm);
-               snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               if (is_8ch) {
-                       snd_hda_codec_write(codec, 0x25, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-                       snd_hda_codec_write(codec, 0x27, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-               }
-       }  else if (spec->codec_type == VT1718S) {
-               /* MUX6 (1eh) = stereo mixer */
-               imux_is_smixer = snd_hda_codec_read(
-                       codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
-               /* inputs */
-               /* PW 5/6/7 (29h/2ah/2bh) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x29, &parm);
-               set_pin_power_state(codec, 0x2a, &parm);
-               set_pin_power_state(codec, 0x2b, &parm);
-               if (imux_is_smixer)
-                       parm = AC_PWRST_D0;
-               /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
-               snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* outputs */
-               /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x27, &parm);
-               snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* PW2 (26h), AOW2 (ah) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x26, &parm);
-               snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* PW0/1 (24h/25h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x24, &parm);
-               set_pin_power_state(codec, 0x25, &parm);
-               if (!spec->hp_independent_mode) /* check for redirected HP */
-                       set_pin_power_state(codec, 0x28, &parm);
-               snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
-               snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
-                                   imux_is_smixer ? AC_PWRST_D0 : parm);
-               if (spec->hp_independent_mode) {
-                       /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
-                       parm = AC_PWRST_D3;
-                       set_pin_power_state(codec, 0x28, &parm);
-                       snd_hda_codec_write(codec, 0x1b, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-                       snd_hda_codec_write(codec, 0x34, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-                       snd_hda_codec_write(codec, 0xc, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-               }
-       } else if (spec->codec_type == VT1716S) {
-               unsigned int mono_out, present;
-               /* SW0 (17h) = stereo mixer */
-               imux_is_smixer = snd_hda_codec_read(
-                       codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) ==  5;
-               /* inputs */
-               /* PW 1/2/5 (1ah/1bh/1eh) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x1a, &parm);
-               set_pin_power_state(codec, 0x1b, &parm);
-               set_pin_power_state(codec, 0x1e, &parm);
-               if (imux_is_smixer)
-                       parm = AC_PWRST_D0;
-               /* SW0 (17h), AIW0(13h) */
-               snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x1e, &parm);
-               /* PW11 (22h) */
-               if (spec->dmic_enabled)
-                       set_pin_power_state(codec, 0x22, &parm);
-               else
-                       snd_hda_codec_write(
-                               codec, 0x22, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-
-               /* SW2(26h), AIW1(14h) */
-               snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* outputs */
-               /* PW0 (19h), SW1 (18h), AOW1 (11h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x19, &parm);
-               /* Smart 5.1 PW2(1bh) */
-               if (spec->smart51_enabled)
-                       set_pin_power_state(codec, 0x1b, &parm);
-               snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* PW7 (23h), SW3 (27h), AOW3 (25h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x23, &parm);
-               /* Smart 5.1 PW1(1ah) */
-               if (spec->smart51_enabled)
-                       set_pin_power_state(codec, 0x1a, &parm);
-               snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* Smart 5.1 PW5(1eh) */
-               if (spec->smart51_enabled)
-                       set_pin_power_state(codec, 0x1e, &parm);
-               snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* Mono out */
-               /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
-               present = snd_hda_jack_detect(codec, 0x1c);
-               if (present)
-                       mono_out = 0;
-               else {
-                       present = snd_hda_jack_detect(codec, 0x1d);
-                       if (!spec->hp_independent_mode && present)
-                               mono_out = 0;
-                       else
-                               mono_out = 1;
-               }
-               parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
-               snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-               snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE,
-                                   parm);
-
-               /* PW 3/4 (1ch/1dh) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x1c, &parm);
-               set_pin_power_state(codec, 0x1d, &parm);
-               /* HP Independent Mode, power on AOW3 */
-               if (spec->hp_independent_mode)
-                       snd_hda_codec_write(codec, 0x25, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-
-               /* force to D0 for internal Speaker */
-               /* MW0 (16h), AOW0 (10h) */
-               snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
-                                   imux_is_smixer ? AC_PWRST_D0 : parm);
-               snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-                                   mono_out ? AC_PWRST_D0 : parm);
-       } else if (spec->codec_type == VT2002P) {
-               unsigned int present;
-               /* MUX9 (1eh) = stereo mixer */
-               imux_is_smixer = snd_hda_codec_read(
-                       codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-               /* inputs */
-               /* PW 5/6/7 (29h/2ah/2bh) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x29, &parm);
-               set_pin_power_state(codec, 0x2a, &parm);
-               set_pin_power_state(codec, 0x2b, &parm);
-               if (imux_is_smixer)
-                       parm = AC_PWRST_D0;
-               /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
-               snd_hda_codec_write(codec, 0x1e, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x1f, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x10, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x11, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-
-               /* outputs */
-               /* AOW0 (8h)*/
-               snd_hda_codec_write(codec, 0x8, 0,
-                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-
-               /* PW4 (26h), MW4 (1ch), MUX4(37h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x26, &parm);
-               snd_hda_codec_write(codec, 0x1c, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x37,
-                                   0, AC_VERB_SET_POWER_STATE, parm);
-
-               /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x25, &parm);
-               snd_hda_codec_write(codec, 0x19, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x35, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               if (spec->hp_independent_mode)  {
-                       snd_hda_codec_write(codec, 0x9, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-               }
-
-               /* Class-D */
-               /* PW0 (24h), MW0(18h), MUX0(34h) */
-               present = snd_hda_jack_detect(codec, 0x25);
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x24, &parm);
-               if (present) {
-                       snd_hda_codec_write(
-                               codec, 0x18, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-                       snd_hda_codec_write(
-                               codec, 0x34, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-               } else {
-                       snd_hda_codec_write(
-                               codec, 0x18, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-                       snd_hda_codec_write(
-                               codec, 0x34, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-               }
-
-               /* Mono Out */
-               /* PW15 (31h), MW8(17h), MUX8(3bh) */
-               present = snd_hda_jack_detect(codec, 0x26);
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x31, &parm);
-               if (present) {
-                       snd_hda_codec_write(
-                               codec, 0x17, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-                       snd_hda_codec_write(
-                               codec, 0x3b, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-               } else {
-                       snd_hda_codec_write(
-                               codec, 0x17, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-                       snd_hda_codec_write(
-                               codec, 0x3b, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-               }
-
-               /* MW9 (21h) */
-               if (imux_is_smixer || !is_aa_path_mute(codec))
-                       snd_hda_codec_write(
-                               codec, 0x21, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-               else
-                       snd_hda_codec_write(
-                               codec, 0x21, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-       } else if (spec->codec_type == VT1812) {
-               unsigned int present;
-               /* MUX10 (1eh) = stereo mixer */
-               imux_is_smixer = snd_hda_codec_read(
-                       codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
-               /* inputs */
-               /* PW 5/6/7 (29h/2ah/2bh) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x29, &parm);
-               set_pin_power_state(codec, 0x2a, &parm);
-               set_pin_power_state(codec, 0x2b, &parm);
-               if (imux_is_smixer)
-                       parm = AC_PWRST_D0;
-               /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
-               snd_hda_codec_write(codec, 0x1e, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x1f, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x10, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x11, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-
-               /* outputs */
-               /* AOW0 (8h)*/
-               snd_hda_codec_write(codec, 0x8, 0,
-                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-
-               /* PW4 (28h), MW4 (18h), MUX4(38h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x28, &parm);
-               snd_hda_codec_write(codec, 0x18, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x38, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-
-               /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x25, &parm);
-               snd_hda_codec_write(codec, 0x15, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x35, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               if (spec->hp_independent_mode)  {
-                       snd_hda_codec_write(codec, 0x9, 0,
-                                           AC_VERB_SET_POWER_STATE, parm);
-               }
-
-               /* Internal Speaker */
-               /* PW0 (24h), MW0(14h), MUX0(34h) */
-               present = snd_hda_jack_detect(codec, 0x25);
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x24, &parm);
-               if (present) {
-                       snd_hda_codec_write(codec, 0x14, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D3);
-                       snd_hda_codec_write(codec, 0x34, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D3);
-               } else {
-                       snd_hda_codec_write(codec, 0x14, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D0);
-                       snd_hda_codec_write(codec, 0x34, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D0);
-               }
-               /* Mono Out */
-               /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
-               present = snd_hda_jack_detect(codec, 0x28);
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x31, &parm);
-               if (present) {
-                       snd_hda_codec_write(codec, 0x1c, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D3);
-                       snd_hda_codec_write(codec, 0x3c, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D3);
-                       snd_hda_codec_write(codec, 0x3e, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D3);
-               } else {
-                       snd_hda_codec_write(codec, 0x1c, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D0);
-                       snd_hda_codec_write(codec, 0x3c, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D0);
-                       snd_hda_codec_write(codec, 0x3e, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D0);
-               }
-
-               /* PW15 (33h), MW15 (1dh), MUX15(3dh) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x33, &parm);
-               snd_hda_codec_write(codec, 0x1d, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x3d, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-
-               /* MW9 (21h) */
-               if (imux_is_smixer || !is_aa_path_mute(codec))
-                       snd_hda_codec_write(
-                               codec, 0x21, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-               else
-                       snd_hda_codec_write(
-                               codec, 0x21, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-       }
-}
-
 /*
  * input MUX handling
  */
@@ -1120,7 +660,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
                                     spec->mux_nids[adc_idx],
                                     &spec->cur_mux[adc_idx]);
        /* update jack power state */
-       set_jack_power_state(codec);
+       set_widgets_power_state(codec);
 
        return ret;
 }
@@ -1168,6 +708,9 @@ static hda_nid_t side_mute_channel(struct via_spec *spec)
        case VT1709_10CH:       return 0x29;
        case VT1708B_8CH:       /* fall thru */
        case VT1708S:           return 0x27;
+       case VT2002P:           return 0x19;
+       case VT1802:            return 0x15;
+       case VT1812:            return 0x15;
        default:                return 0;
        }
 }
@@ -1176,13 +719,22 @@ static int update_side_mute_status(struct hda_codec *codec)
 {
        /* mute side channel */
        struct via_spec *spec = codec->spec;
-       unsigned int parm = spec->hp_independent_mode
-               ? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
+       unsigned int parm;
        hda_nid_t sw3 = side_mute_channel(spec);
 
-       if (sw3)
-               snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                                   parm);
+       if (sw3) {
+               if (VT2002P_COMPATIBLE(spec))
+                       parm = spec->hp_independent_mode ?
+                              AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
+               else
+                       parm = spec->hp_independent_mode ?
+                              AMP_OUT_MUTE : AMP_OUT_UNMUTE;
+               snd_hda_codec_write(codec, sw3, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, parm);
+               if (spec->codec_type == VT1812)
+                       snd_hda_codec_write(codec, 0x1d, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE, parm);
+       }
        return 0;
 }
 
@@ -1217,15 +769,14 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
            || spec->codec_type == VT1702
            || spec->codec_type == VT1718S
            || spec->codec_type == VT1716S
-           || spec->codec_type == VT2002P
-           || spec->codec_type == VT1812) {
+           || VT2002P_COMPATIBLE(spec)) {
                activate_ctl(codec, "Headphone Playback Volume",
                             spec->hp_independent_mode);
                activate_ctl(codec, "Headphone Playback Switch",
                             spec->hp_independent_mode);
        }
        /* update jack power state */
-       set_jack_power_state(codec);
+       set_widgets_power_state(codec);
        return 0;
 }
 
@@ -1256,6 +807,7 @@ static int via_hp_build(struct hda_codec *codec)
                nid = 0x34;
                break;
        case VT2002P:
+       case VT1802:
                nid = 0x35;
                break;
        case VT1812:
@@ -1447,7 +999,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
                }
        }
        spec->smart51_enabled = *ucontrol->value.integer.value;
-       set_jack_power_state(codec);
+       set_widgets_power_state(codec);
        return 1;
 }
 
@@ -1473,6 +1025,11 @@ static int via_smart51_build(struct via_spec *spec)
        hda_nid_t nid;
        int i;
 
+       if (!cfg)
+               return 0;
+       if (cfg->line_outs > 2)
+               return 0;
+
        knew = via_clone_control(spec, &via_smart51_mixer[0]);
        if (knew == NULL)
                return -ENOMEM;
@@ -1543,6 +1100,7 @@ static int is_aa_path_mute(struct hda_codec *codec)
                break;
        case VT2002P:
        case VT1812:
+       case VT1802:
                nid_mixer = 0x21;
                start_idx = 0;
                end_idx = 2;
@@ -1607,6 +1165,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
                break;
        case VT2002P:
        case VT1812:
+       case VT1802:
                verb = 0xf93;
                parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
                break;
@@ -1650,6 +1209,8 @@ static struct hda_verb vt1708_volume_init_verbs[] = {
        {0x20, AC_VERB_SET_CONNECT_SEL, 0},
        /* PW9 Output enable */
        {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* power down jack detect function */
+       {0x1, 0xf81, 0x1},
        { }
 };
 
@@ -1971,7 +1532,7 @@ static int via_build_controls(struct hda_codec *codec)
        }
 
        /* init power states */
-       set_jack_power_state(codec);
+       set_widgets_power_state(codec);
        analog_low_current_mode(codec, 1);
 
        via_free_kctls(codec); /* no longer needed */
@@ -2135,7 +1696,7 @@ static void via_speaker_automute(struct hda_codec *codec)
        unsigned int hp_present;
        struct via_spec *spec = codec->spec;
 
-       if (spec->codec_type != VT2002P && spec->codec_type != VT1812)
+       if (!VT2002P_COMPATIBLE(spec))
                return;
 
        hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
@@ -2194,17 +1755,21 @@ static void via_unsol_event(struct hda_codec *codec,
                                  unsigned int res)
 {
        res >>= 26;
-       if (res & VIA_HP_EVENT)
+
+       if (res & VIA_JACK_EVENT)
+               set_widgets_power_state(codec);
+
+       res &= ~VIA_JACK_EVENT;
+
+       if (res == VIA_HP_EVENT)
                via_hp_automute(codec);
-       if (res & VIA_GPIO_EVENT)
+       else if (res == VIA_GPIO_EVENT)
                via_gpio_control(codec);
-       if (res & VIA_JACK_EVENT)
-               set_jack_power_state(codec);
-       if (res & VIA_MONO_EVENT)
+       else if (res == VIA_MONO_EVENT)
                via_mono_automute(codec);
-       if (res & VIA_SPEAKER_EVENT)
+       else if (res == VIA_SPEAKER_EVENT)
                via_speaker_automute(codec);
-       if (res & VIA_BIND_HP_EVENT)
+       else if (res == VIA_BIND_HP_EVENT)
                via_hp_bind_automute(codec);
 }
 
@@ -2623,7 +2188,8 @@ static int via_auto_init(struct hda_codec *codec)
        via_auto_init_multi_out(codec);
        via_auto_init_hp_out(codec);
        via_auto_init_analog_input(codec);
-       if (spec->codec_type == VT2002P || spec->codec_type == VT1812) {
+
+       if (VT2002P_COMPATIBLE(spec)) {
                via_hp_bind_automute(codec);
        } else {
                via_hp_automute(codec);
@@ -3646,6 +3212,87 @@ static struct hda_amp_list vt1708B_loopbacks[] = {
        { } /* end */
 };
 #endif
+
+static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int imux_is_smixer;
+       unsigned int parm;
+       int is_8ch = 0;
+       if ((spec->codec_type != VT1708B_4CH) &&
+           (codec->vendor_id != 0x11064397))
+               is_8ch = 1;
+
+       /* SW0 (17h) = stereo mixer */
+       imux_is_smixer =
+       (snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
+        == ((spec->codec_type == VT1708S) ? 5 : 0));
+       /* inputs */
+       /* PW 1/2/5 (1ah/1bh/1eh) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x1a, &parm);
+       set_pin_power_state(codec, 0x1b, &parm);
+       set_pin_power_state(codec, 0x1e, &parm);
+       if (imux_is_smixer)
+               parm = AC_PWRST_D0;
+       /* SW0 (17h), AIW 0/1 (13h/14h) */
+       snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* outputs */
+       /* PW0 (19h), SW1 (18h), AOW1 (11h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x19, &parm);
+       if (spec->smart51_enabled)
+               set_pin_power_state(codec, 0x1b, &parm);
+       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* PW6 (22h), SW2 (26h), AOW2 (24h) */
+       if (is_8ch) {
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x22, &parm);
+               if (spec->smart51_enabled)
+                       set_pin_power_state(codec, 0x1a, &parm);
+               snd_hda_codec_write(codec, 0x26, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x24, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       } else if (codec->vendor_id == 0x11064397) {
+               /* PW7(23h), SW2(27h), AOW2(25h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x23, &parm);
+               if (spec->smart51_enabled)
+                       set_pin_power_state(codec, 0x1a, &parm);
+               snd_hda_codec_write(codec, 0x27, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x25, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       }
+
+       /* PW 3/4/7 (1ch/1dh/23h) */
+       parm = AC_PWRST_D3;
+       /* force to D0 for internal Speaker */
+       set_pin_power_state(codec, 0x1c, &parm);
+       set_pin_power_state(codec, 0x1d, &parm);
+       if (is_8ch)
+               set_pin_power_state(codec, 0x23, &parm);
+
+       /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
+       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+                           imux_is_smixer ? AC_PWRST_D0 : parm);
+       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+       if (is_8ch) {
+               snd_hda_codec_write(codec, 0x25, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x27, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode)
+               snd_hda_codec_write(codec, 0x25, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+}
+
 static int patch_vt1708S(struct hda_codec *codec);
 static int patch_vt1708B_8ch(struct hda_codec *codec)
 {
@@ -3696,6 +3343,8 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
        spec->loopback.amplist = vt1708B_loopbacks;
 #endif
 
+       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
+
        return 0;
 }
 
@@ -3746,6 +3395,8 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
        spec->loopback.amplist = vt1708B_loopbacks;
 #endif
 
+       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
+
        return 0;
 }
 
@@ -3814,6 +3465,18 @@ static struct hda_verb vt1708S_uniwill_init_verbs[] = {
        { }
 };
 
+static struct hda_verb vt1705_uniwill_init_verbs[] = {
+       {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       { }
+};
+
 static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
        .substreams = 2,
        .channels_min = 2,
@@ -3827,6 +3490,19 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
        },
 };
 
+static struct hda_pcm_stream vt1705_pcm_analog_playback = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 6,
+       .nid = 0x10, /* NID to query formats and rates */
+       .ops = {
+               .open = via_playback_pcm_open,
+               .prepare = via_playback_multi_pcm_prepare,
+               .cleanup = via_playback_multi_pcm_cleanup,
+               .close = via_pcm_open_close
+       },
+};
+
 static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
        .substreams = 2,
        .channels_min = 2,
@@ -3873,7 +3549,10 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
                                spec->multiout.dac_nids[i] = 0x10;
                                break;
                        case AUTO_SEQ_CENLFE:
-                               spec->multiout.dac_nids[i] = 0x24;
+                               if (spec->codec->vendor_id == 0x11064397)
+                                       spec->multiout.dac_nids[i] = 0x25;
+                               else
+                                       spec->multiout.dac_nids[i] = 0x24;
                                break;
                        case AUTO_SEQ_SURROUND:
                                spec->multiout.dac_nids[i] = 0x11;
@@ -3889,22 +3568,28 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
        if (cfg->line_outs == 1) {
                spec->multiout.num_dacs = 3;
                spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11;
-               spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24;
+               if (spec->codec->vendor_id == 0x11064397)
+                       spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x25;
+               else
+                       spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24;
        }
 
        return 0;
 }
 
 /* add playback controls from the parsed DAC table */
-static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
+static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec,
                                             const struct auto_pin_cfg *cfg)
 {
+       struct via_spec *spec = codec->spec;
        char name[32];
        static const char * const chname[4] = {
                "Front", "Surround", "C/LFE", "Side"
        };
-       hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
-       hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
+       hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25},
+                                    {0x10, 0x11, 0x25, 0} };
+       hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27},
+                                     {0x1C, 0x18, 0x27, 0} };
        hda_nid_t nid, nid_vol, nid_mute;
        int i, err;
 
@@ -3915,8 +3600,15 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
                if (!nid && i > AUTO_SEQ_CENLFE)
                        continue;
 
-               nid_vol = nid_vols[i];
-               nid_mute = nid_mutes[i];
+               if (codec->vendor_id == 0x11064397) {
+                       nid_vol = nid_vols[1][i];
+                       nid_mute = nid_mutes[1][i];
+               } else {
+                       nid_vol = nid_vols[0][i];
+                       nid_mute = nid_mutes[0][i];
+               }
+               if (!nid_vol && !nid_mute)
+                       continue;
 
                if (i == AUTO_SEQ_CENLFE) {
                        /* Center/LFE */
@@ -4070,7 +3762,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
        if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
                return 0; /* can't find valid BIOS pin config */
 
-       err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
        err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
@@ -4137,17 +3829,29 @@ static int patch_vt1708S(struct hda_codec *codec)
        }
 
        spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
+       if (codec->vendor_id == 0x11064397)
+               spec->init_verbs[spec->num_iverbs++] =
+                       vt1705_uniwill_init_verbs;
+       else
+               spec->init_verbs[spec->num_iverbs++] =
+                       vt1708S_uniwill_init_verbs;
 
        if (codec->vendor_id == 0x11060440)
                spec->stream_name_analog = "VT1818S Analog";
+       else if (codec->vendor_id == 0x11064397)
+               spec->stream_name_analog = "VT1705 Analog";
        else
                spec->stream_name_analog = "VT1708S Analog";
-       spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
+       if (codec->vendor_id == 0x11064397)
+               spec->stream_analog_playback = &vt1705_pcm_analog_playback;
+       else
+               spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
        spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
 
        if (codec->vendor_id == 0x11060440)
                spec->stream_name_digital = "VT1818S Digital";
+       else if (codec->vendor_id == 0x11064397)
+               spec->stream_name_digital = "VT1705 Digital";
        else
                spec->stream_name_digital = "VT1708S Digital";
        spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
@@ -4185,6 +3889,15 @@ static int patch_vt1708S(struct hda_codec *codec)
                spec->stream_name_analog = "VT1818S Analog";
                spec->stream_name_digital = "VT1818S Digital";
        }
+       /* correct names for VT1705 */
+       if (codec->vendor_id == 0x11064397)     {
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
+               snprintf(codec->bus->card->mixername,
+                        sizeof(codec->bus->card->mixername),
+                        "%s %s", codec->vendor_name, codec->chip_name);
+       }
+       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
        return 0;
 }
 
@@ -4442,6 +4155,37 @@ static struct hda_amp_list vt1702_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt1702(struct hda_codec *codec)
+{
+       int imux_is_smixer =
+       snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+       unsigned int parm;
+       /* inputs */
+       /* PW 1/2/5 (14h/15h/18h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x14, &parm);
+       set_pin_power_state(codec, 0x15, &parm);
+       set_pin_power_state(codec, 0x18, &parm);
+       if (imux_is_smixer)
+               parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */
+       /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
+       snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* outputs */
+       /* PW 3/4 (16h/17h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x17, &parm);
+       set_pin_power_state(codec, 0x16, &parm);
+       /* MW0 (1ah), AOW 0/1 (10h/1dh) */
+       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
+                           imux_is_smixer ? AC_PWRST_D0 : parm);
+       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
+}
+
 static int patch_vt1702(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -4488,6 +4232,7 @@ static int patch_vt1702(struct hda_codec *codec)
        spec->loopback.amplist = vt1702_loopbacks;
 #endif
 
+       spec->set_widgets_power_state =  set_widgets_power_state_vt1702;
        return 0;
 }
 
@@ -4523,7 +4268,8 @@ static struct hda_verb vt1718S_volume_init_verbs[] = {
        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
-
+       /* Enable MW0 adjust Gain 5 */
+       {0x1, 0xfb2, 0x10},
        /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
         * mixer widget
         */
@@ -4532,7 +4278,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = {
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
 
        /* Setup default input of Front HP to MW9 */
        {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
@@ -4829,6 +4575,72 @@ static struct hda_amp_list vt1718S_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int imux_is_smixer;
+       unsigned int parm;
+       /* MUX6 (1eh) = stereo mixer */
+       imux_is_smixer =
+       snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+       /* inputs */
+       /* PW 5/6/7 (29h/2ah/2bh) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x29, &parm);
+       set_pin_power_state(codec, 0x2a, &parm);
+       set_pin_power_state(codec, 0x2b, &parm);
+       if (imux_is_smixer)
+               parm = AC_PWRST_D0;
+       /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
+       snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* outputs */
+       /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x27, &parm);
+       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* PW2 (26h), AOW2 (ah) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x26, &parm);
+       if (spec->smart51_enabled)
+               set_pin_power_state(codec, 0x2b, &parm);
+       snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* PW0 (24h), AOW0 (8h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x24, &parm);
+       if (!spec->hp_independent_mode) /* check for redirected HP */
+               set_pin_power_state(codec, 0x28, &parm);
+       snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
+       /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
+       snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
+                           imux_is_smixer ? AC_PWRST_D0 : parm);
+
+       /* PW1 (25h), AOW1 (9h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x25, &parm);
+       if (spec->smart51_enabled)
+               set_pin_power_state(codec, 0x2a, &parm);
+       snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       if (spec->hp_independent_mode) {
+               /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x28, &parm);
+               snd_hda_codec_write(codec, 0x1b, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x34, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0xc, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       }
+}
+
 static int patch_vt1718S(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -4890,6 +4702,8 @@ static int patch_vt1718S(struct hda_codec *codec)
        spec->loopback.amplist = vt1718S_loopbacks;
 #endif
 
+       spec->set_widgets_power_state =  set_widgets_power_state_vt1718S;
+
        return 0;
 }
 
@@ -4929,8 +4743,7 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
        snd_hda_codec_write(codec, 0x26, 0,
                                               AC_VERB_SET_CONNECT_SEL, index);
        spec->dmic_enabled = index;
-       set_jack_power_state(codec);
-
+       set_widgets_power_state(codec);
        return 1;
 }
 
@@ -5289,6 +5102,99 @@ static struct hda_amp_list vt1716S_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int imux_is_smixer;
+       unsigned int parm;
+       unsigned int mono_out, present;
+       /* SW0 (17h) = stereo mixer */
+       imux_is_smixer =
+       (snd_hda_codec_read(codec, 0x17, 0,
+                           AC_VERB_GET_CONNECT_SEL, 0x00) ==  5);
+       /* inputs */
+       /* PW 1/2/5 (1ah/1bh/1eh) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x1a, &parm);
+       set_pin_power_state(codec, 0x1b, &parm);
+       set_pin_power_state(codec, 0x1e, &parm);
+       if (imux_is_smixer)
+               parm = AC_PWRST_D0;
+       /* SW0 (17h), AIW0(13h) */
+       snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x1e, &parm);
+       /* PW11 (22h) */
+       if (spec->dmic_enabled)
+               set_pin_power_state(codec, 0x22, &parm);
+       else
+               snd_hda_codec_write(codec, 0x22, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+       /* SW2(26h), AIW1(14h) */
+       snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* outputs */
+       /* PW0 (19h), SW1 (18h), AOW1 (11h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x19, &parm);
+       /* Smart 5.1 PW2(1bh) */
+       if (spec->smart51_enabled)
+               set_pin_power_state(codec, 0x1b, &parm);
+       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* PW7 (23h), SW3 (27h), AOW3 (25h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x23, &parm);
+       /* Smart 5.1 PW1(1ah) */
+       if (spec->smart51_enabled)
+               set_pin_power_state(codec, 0x1a, &parm);
+       snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* Smart 5.1 PW5(1eh) */
+       if (spec->smart51_enabled)
+               set_pin_power_state(codec, 0x1e, &parm);
+       snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* Mono out */
+       /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
+       present = snd_hda_jack_detect(codec, 0x1c);
+
+       if (present)
+               mono_out = 0;
+       else {
+               present = snd_hda_jack_detect(codec, 0x1d);
+               if (!spec->hp_independent_mode && present)
+                       mono_out = 0;
+               else
+                       mono_out = 1;
+       }
+       parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
+       snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* PW 3/4 (1ch/1dh) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x1c, &parm);
+       set_pin_power_state(codec, 0x1d, &parm);
+       /* HP Independent Mode, power on AOW3 */
+       if (spec->hp_independent_mode)
+               snd_hda_codec_write(codec, 0x25, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+
+       /* force to D0 for internal Speaker */
+       /* MW0 (16h), AOW0 (10h) */
+       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+                           imux_is_smixer ? AC_PWRST_D0 : parm);
+       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+                           mono_out ? AC_PWRST_D0 : parm);
+}
+
 static int patch_vt1716S(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -5343,6 +5249,7 @@ static int patch_vt1716S(struct hda_codec *codec)
        spec->loopback.amplist = vt1716S_loopbacks;
 #endif
 
+       spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
        return 0;
 }
 
@@ -5373,6 +5280,10 @@ static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
 };
 
 static struct hda_verb vt2002P_volume_init_verbs[] = {
+       /* Class-D speaker related verbs */
+       {0x1, 0xfe0, 0x4},
+       {0x1, 0xfe9, 0x80},
+       {0x1, 0xfe2, 0x22},
        /*
         * Unmute ADC0-1 and set the default input to mic-in
         */
@@ -5423,6 +5334,57 @@ static struct hda_verb vt2002P_volume_init_verbs[] = {
        {0x1, 0xfb8, 0x88},
        { }
 };
+static struct hda_verb vt1802_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-1 and set the default input to mic-in
+        */
+       {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        */
+       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /* MUX Indices: Mic = 0 */
+       {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* PW9 Output enable */
+       {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xfb9, 0x24},
+
+       /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* set MUX0/1/4/8 = 0 (AOW0) */
+       {0x34, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x35, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x38, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* set PW0 index=0 (MW0) */
+       {0x24, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* Enable AOW0 to MW9 */
+       {0x1, 0xfb8, 0x88},
+       { }
+};
 
 
 static struct hda_verb vt2002P_uniwill_init_verbs[] = {
@@ -5435,6 +5397,16 @@ static struct hda_verb vt2002P_uniwill_init_verbs[] = {
        {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
        { }
 };
+static struct hda_verb vt1802_uniwill_init_verbs[] = {
+       {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+       {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
+        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+       {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+       { }
+};
 
 static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
        .substreams = 2,
@@ -5491,10 +5463,15 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
                                             const struct auto_pin_cfg *cfg)
 {
        int err;
+       hda_nid_t sw_nid;
 
        if (!cfg->line_out_pins[0])
                return -1;
 
+       if (spec->codec_type == VT1802)
+               sw_nid = 0x28;
+       else
+               sw_nid = 0x26;
 
        /* Line-Out: PortE */
        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
@@ -5504,7 +5481,7 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
                return err;
        err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
                              "Master Front Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
+                             HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT));
        if (err < 0)
                return err;
 
@@ -5613,6 +5590,116 @@ static struct hda_amp_list vt2002P_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int imux_is_smixer;
+       unsigned int parm;
+       unsigned int present;
+       /* MUX9 (1eh) = stereo mixer */
+       imux_is_smixer =
+       snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+       /* inputs */
+       /* PW 5/6/7 (29h/2ah/2bh) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x29, &parm);
+       set_pin_power_state(codec, 0x2a, &parm);
+       set_pin_power_state(codec, 0x2b, &parm);
+       parm = AC_PWRST_D0;
+       /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
+       snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* outputs */
+       /* AOW0 (8h)*/
+       snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       if (spec->codec_type == VT1802) {
+               /* PW4 (28h), MW4 (18h), MUX4(38h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x28, &parm);
+               snd_hda_codec_write(codec, 0x18, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x38, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       } else {
+               /* PW4 (26h), MW4 (1ch), MUX4(37h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x26, &parm);
+               snd_hda_codec_write(codec, 0x1c, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x37, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       }
+
+       if (spec->codec_type == VT1802) {
+               /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x25, &parm);
+               snd_hda_codec_write(codec, 0x15, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x35, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       } else {
+               /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x25, &parm);
+               snd_hda_codec_write(codec, 0x19, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x35, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       }
+
+       if (spec->hp_independent_mode)
+               snd_hda_codec_write(codec, 0x9, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+       /* Class-D */
+       /* PW0 (24h), MW0(18h/14h), MUX0(34h) */
+       present = snd_hda_jack_detect(codec, 0x25);
+
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x24, &parm);
+       parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
+       if (spec->codec_type == VT1802)
+               snd_hda_codec_write(codec, 0x14, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       else
+               snd_hda_codec_write(codec, 0x18, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* Mono Out */
+       present = snd_hda_jack_detect(codec, 0x26);
+
+       parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
+       if (spec->codec_type == VT1802) {
+               /* PW15 (33h), MW8(1ch), MUX8(3ch) */
+               snd_hda_codec_write(codec, 0x33, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x1c, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x3c, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       } else {
+               /* PW15 (31h), MW8(17h), MUX8(3bh) */
+               snd_hda_codec_write(codec, 0x31, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x17, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x3b, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       }
+       /* MW9 (21h) */
+       if (imux_is_smixer || !is_aa_path_mute(codec))
+               snd_hda_codec_write(codec, 0x21, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+       else
+               snd_hda_codec_write(codec, 0x21, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+}
 
 /* patch for vt2002P */
 static int patch_vt2002P(struct hda_codec *codec)
@@ -5635,14 +5722,31 @@ static int patch_vt2002P(struct hda_codec *codec)
                       "from BIOS.  Using genenic mode...\n");
        }
 
-       spec->init_verbs[spec->num_iverbs++]  = vt2002P_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
+       if (spec->codec_type == VT1802)
+               spec->init_verbs[spec->num_iverbs++]  =
+                       vt1802_volume_init_verbs;
+       else
+               spec->init_verbs[spec->num_iverbs++]  =
+                       vt2002P_volume_init_verbs;
+
+       if (spec->codec_type == VT1802)
+               spec->init_verbs[spec->num_iverbs++] =
+                       vt1802_uniwill_init_verbs;
+       else
+               spec->init_verbs[spec->num_iverbs++] =
+                       vt2002P_uniwill_init_verbs;
 
-       spec->stream_name_analog = "VT2002P Analog";
+       if (spec->codec_type == VT1802)
+               spec->stream_name_analog = "VT1802 Analog";
+       else
+               spec->stream_name_analog = "VT2002P Analog";
        spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
        spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
 
-       spec->stream_name_digital = "VT2002P Digital";
+       if (spec->codec_type == VT1802)
+               spec->stream_name_digital = "VT1802 Digital";
+       else
+               spec->stream_name_digital = "VT2002P Digital";
        spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
 
        if (!spec->adc_nids && spec->input_mux) {
@@ -5664,6 +5768,7 @@ static int patch_vt2002P(struct hda_codec *codec)
        spec->loopback.amplist = vt2002P_loopbacks;
 #endif
 
+       spec->set_widgets_power_state =  set_widgets_power_state_vt2002P;
        return 0;
 }
 
@@ -5935,6 +6040,97 @@ static struct hda_amp_list vt1812_loopbacks[] = {
 };
 #endif
 
+static void set_widgets_power_state_vt1812(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int imux_is_smixer =
+       snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+       unsigned int parm;
+       unsigned int present;
+       /* MUX10 (1eh) = stereo mixer */
+       imux_is_smixer =
+       snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+       /* inputs */
+       /* PW 5/6/7 (29h/2ah/2bh) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x29, &parm);
+       set_pin_power_state(codec, 0x2a, &parm);
+       set_pin_power_state(codec, 0x2b, &parm);
+       parm = AC_PWRST_D0;
+       /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
+       snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* outputs */
+       /* AOW0 (8h)*/
+       snd_hda_codec_write(codec, 0x8, 0,
+                           AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+       /* PW4 (28h), MW4 (18h), MUX4(38h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x28, &parm);
+       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x25, &parm);
+       snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm);
+       if (spec->hp_independent_mode)
+               snd_hda_codec_write(codec, 0x9, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+       /* Internal Speaker */
+       /* PW0 (24h), MW0(14h), MUX0(34h) */
+       present = snd_hda_jack_detect(codec, 0x25);
+
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x24, &parm);
+       if (present) {
+               snd_hda_codec_write(codec, 0x14, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+               snd_hda_codec_write(codec, 0x34, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+       } else {
+               snd_hda_codec_write(codec, 0x14, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+               snd_hda_codec_write(codec, 0x34, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+       }
+
+
+       /* Mono Out */
+       /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
+       present = snd_hda_jack_detect(codec, 0x28);
+
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x31, &parm);
+       if (present) {
+               snd_hda_codec_write(codec, 0x1c, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+               snd_hda_codec_write(codec, 0x3c, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+               snd_hda_codec_write(codec, 0x3e, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+       } else {
+               snd_hda_codec_write(codec, 0x1c, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+               snd_hda_codec_write(codec, 0x3c, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+               snd_hda_codec_write(codec, 0x3e, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+       }
+
+       /* PW15 (33h), MW15 (1dh), MUX15(3dh) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x33, &parm);
+       snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm);
+
+}
 
 /* patch for vt1812 */
 static int patch_vt1812(struct hda_codec *codec)
@@ -5988,6 +6184,7 @@ static int patch_vt1812(struct hda_codec *codec)
        spec->loopback.amplist = vt1812_loopbacks;
 #endif
 
+       spec->set_widgets_power_state =  set_widgets_power_state_vt1812;
        return 0;
 }
 
@@ -6039,7 +6236,7 @@ static struct hda_codec_preset snd_hda_preset_via[] = {
          .patch = patch_vt1708S},
        { .id = 0x11063397, .name = "VT1708S",
          .patch = patch_vt1708S},
-       { .id = 0x11064397, .name = "VT1708S",
+       { .id = 0x11064397, .name = "VT1705",
          .patch = patch_vt1708S},
        { .id = 0x11065397, .name = "VT1708S",
          .patch = patch_vt1708S},
@@ -6080,6 +6277,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = {
        { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
        { .id = 0x11060440, .name = "VT1818S",
          .patch = patch_vt1708S},
+       { .id = 0x11060446, .name = "VT1802",
+               .patch = patch_vt2002P},
+       { .id = 0x11068446, .name = "VT1802",
+               .patch = patch_vt2002P},
        {} /* terminator */
 };