Merge branch 'for-3.12' into for-next
authorTakashi Iwai <tiwai@suse.de>
Mon, 15 Jul 2013 10:09:28 +0000 (12:09 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 15 Jul 2013 10:09:28 +0000 (12:09 +0200)
sound/firewire/speakers.c
sound/pci/hda/patch_analog.c
sound/pci/rme9652/hdspm.c

index 2c63865..fe9e6e2 100644 (file)
@@ -49,7 +49,6 @@ struct fwspk {
        struct snd_card *card;
        struct fw_unit *unit;
        const struct device_info *device_info;
-       struct snd_pcm_substream *pcm;
        struct mutex mutex;
        struct cmp_connection connection;
        struct amdtp_out_stream stream;
@@ -363,8 +362,7 @@ static int fwspk_create_pcm(struct fwspk *fwspk)
                return err;
        pcm->private_data = fwspk;
        strcpy(pcm->name, fwspk->device_info->short_name);
-       fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
-       fwspk->pcm->ops = &ops;
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
        return 0;
 }
 
index d97f0d6..0cbdd87 100644 (file)
@@ -32,7 +32,6 @@
 #include "hda_jack.h"
 #include "hda_generic.h"
 
-#define ENABLE_AD_STATIC_QUIRKS
 
 struct ad198x_spec {
        struct hda_gen_spec gen;
@@ -43,114 +42,8 @@ struct ad198x_spec {
        hda_nid_t eapd_nid;
 
        unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-       const struct snd_kcontrol_new *mixers[6];
-       int num_mixers;
-       const struct hda_verb *init_verbs[6];   /* initialization verbs
-                                                * don't forget NULL termination!
-                                                */
-       unsigned int num_init_verbs;
-
-       /* playback */
-       struct hda_multi_out multiout;  /* playback set-up
-                                        * max_channels, dacs must be set
-                                        * dig_out_nid and hp_nid are optional
-                                        */
-       unsigned int cur_eapd;
-       unsigned int need_dac_fix;
-
-       /* capture */
-       unsigned int num_adc_nids;
-       const hda_nid_t *adc_nids;
-       hda_nid_t dig_in_nid;           /* digital-in NID; optional */
-
-       /* capture source */
-       const struct hda_input_mux *input_mux;
-       const hda_nid_t *capsrc_nids;
-       unsigned int cur_mux[3];
-
-       /* channel model */
-       const struct hda_channel_mode *channel_mode;
-       int num_channel_mode;
-
-       /* PCM information */
-       struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
-
-       unsigned int spdif_route;
-
-       unsigned int jack_present: 1;
-       unsigned int inv_jack_detect: 1;/* inverted jack-detection */
-       unsigned int analog_beep: 1;    /* analog beep input present */
-       unsigned int avoid_init_slave_vol:1;
-
-#ifdef CONFIG_PM
-       struct hda_loopback_check loopback;
-#endif
-       /* for virtual master */
-       hda_nid_t vmaster_nid;
-       const char * const *slave_vols;
-       const char * const *slave_sws;
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-};
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-/*
- * input MUX handling (common part)
- */
-static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       return snd_hda_input_mux_info(spec->input_mux, uinfo);
-}
-
-static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
-       ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
-       return 0;
-}
-
-static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
-       return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                    spec->capsrc_nids[adc_idx],
-                                    &spec->cur_mux[adc_idx]);
-}
-
-/*
- * initialization (common callbacks)
- */
-static int ad198x_init(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_init_verbs; i++)
-               snd_hda_sequence_write(codec, spec->init_verbs[i]);
-       return 0;
-}
-
-static const char * const ad_slave_pfxs[] = {
-       "Front", "Surround", "Center", "LFE", "Side",
-       "Headphone", "Mono", "Speaker", "IEC958",
-       NULL
 };
 
-static const char * const ad1988_6stack_fp_slave_pfxs[] = {
-       "Front", "Surround", "Center", "LFE", "Side", "IEC958",
-       NULL
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
@@ -160,12 +53,6 @@ static const struct snd_kcontrol_new ad_beep_mixer[] = {
        { } /* end */
 };
 
-static const struct snd_kcontrol_new ad_beep2_mixer[] = {
-       HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
-       { } /* end */
-};
-
 #define set_beep_amp(spec, nid, idx, dir) \
        ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
 #else
@@ -181,8 +68,7 @@ static int create_beep_ctls(struct hda_codec *codec)
        if (!spec->beep_amp)
                return 0;
 
-       knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
-       for ( ; knew->name; knew++) {
+       for (knew = ad_beep_mixer ; knew->name; knew++) {
                int err;
                struct snd_kcontrol *kctl;
                kctl = snd_ctl_new1(knew, codec);
@@ -199,268 +85,6 @@ static int create_beep_ctls(struct hda_codec *codec)
 #define create_beep_ctls(codec)                0
 #endif
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int ad198x_build_controls(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       struct snd_kcontrol *kctl;
-       unsigned int i;
-       int err;
-
-       for (i = 0; i < spec->num_mixers; i++) {
-               err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
-               if (err < 0)
-                       return err;
-       }
-       if (spec->multiout.dig_out_nid) {
-               err = snd_hda_create_spdif_out_ctls(codec,
-                                                   spec->multiout.dig_out_nid,
-                                                   spec->multiout.dig_out_nid);
-               if (err < 0)
-                       return err;
-               err = snd_hda_create_spdif_share_sw(codec,
-                                                   &spec->multiout);
-               if (err < 0)
-                       return err;
-               spec->multiout.share_spdif = 1;
-       } 
-       if (spec->dig_in_nid) {
-               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
-               if (err < 0)
-                       return err;
-       }
-
-       /* create beep controls if needed */
-       err = create_beep_ctls(codec);
-       if (err < 0)
-               return err;
-
-       /* if we have no master control, let's create it */
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
-               unsigned int vmaster_tlv[4];
-               snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
-                                       HDA_OUTPUT, vmaster_tlv);
-               err = __snd_hda_add_vmaster(codec, "Master Playback Volume",
-                                         vmaster_tlv,
-                                         (spec->slave_vols ?
-                                          spec->slave_vols : ad_slave_pfxs),
-                                         "Playback Volume",
-                                         !spec->avoid_init_slave_vol, NULL);
-               if (err < 0)
-                       return err;
-       }
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
-               err = snd_hda_add_vmaster(codec, "Master Playback Switch",
-                                         NULL,
-                                         (spec->slave_sws ?
-                                          spec->slave_sws : ad_slave_pfxs),
-                                         "Playback Switch");
-               if (err < 0)
-                       return err;
-       }
-
-       /* assign Capture Source enums to NID */
-       kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
-       if (!kctl)
-               kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
-       for (i = 0; kctl && i < kctl->count; i++) {
-               err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
-               if (err < 0)
-                       return err;
-       }
-
-       /* assign IEC958 enums to NID */
-       kctl = snd_hda_find_mixer_ctl(codec,
-                       SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
-       if (kctl) {
-               err = snd_hda_add_nid(codec, kctl, 0,
-                                     spec->multiout.dig_out_nid);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
-}
-#endif
-
-/*
- * Analog playback callbacks
- */
-static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
-                                            hinfo);
-}
-
-static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                      struct hda_codec *codec,
-                                      unsigned int stream_tag,
-                                      unsigned int format,
-                                      struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
-                                               format, substream);
-}
-
-static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                      struct hda_codec *codec,
-                                      struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
-
-/*
- * Digital out
- */
-static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                        struct hda_codec *codec,
-                                        struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                          struct hda_codec *codec,
-                                          unsigned int stream_tag,
-                                          unsigned int format,
-                                          struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-                                            format, substream);
-}
-
-static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                          struct hda_codec *codec,
-                                          struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
-}
-
-/*
- * Analog capture
- */
-static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                     struct hda_codec *codec,
-                                     unsigned int stream_tag,
-                                     unsigned int format,
-                                     struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
-                                  stream_tag, 0, format);
-       return 0;
-}
-
-static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                     struct hda_codec *codec,
-                                     struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
-       return 0;
-}
-
-/*
- */
-static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 6, /* changed later */
-       .nid = 0, /* fill later */
-       .ops = {
-               .open = ad198x_playback_pcm_open,
-               .prepare = ad198x_playback_pcm_prepare,
-               .cleanup = ad198x_playback_pcm_cleanup,
-       },
-};
-
-static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0, /* fill later */
-       .ops = {
-               .prepare = ad198x_capture_pcm_prepare,
-               .cleanup = ad198x_capture_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0, /* fill later */
-       .ops = {
-               .open = ad198x_dig_playback_pcm_open,
-               .close = ad198x_dig_playback_pcm_close,
-               .prepare = ad198x_dig_playback_pcm_prepare,
-               .cleanup = ad198x_dig_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in alc_build_pcms */
-};
-
-static int ad198x_build_pcms(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       info->name = "AD198x Analog";
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
-       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
-
-       if (spec->multiout.dig_out_nid) {
-               info++;
-               codec->num_pcms++;
-               codec->spdif_status_reset = 1;
-               info->name = "AD198x Digital";
-               info->pcm_type = HDA_PCM_TYPE_SPDIF;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
-               if (spec->dig_in_nid) {
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
-               }
-       }
-
-       return 0;
-}
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 
 static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
                                hda_nid_t hp)
@@ -507,18 +131,6 @@ static void ad198x_shutup(struct hda_codec *codec)
        ad198x_power_eapd(codec);
 }
 
-static void ad198x_free(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       if (!spec)
-               return;
-
-       snd_hda_gen_spec_free(&spec->gen);
-       kfree(spec);
-       snd_hda_detach_beep_device(codec);
-}
-
 #ifdef CONFIG_PM
 static int ad198x_suspend(struct hda_codec *codec)
 {
@@ -527,65 +139,6 @@ static int ad198x_suspend(struct hda_codec *codec)
 }
 #endif
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const struct hda_codec_ops ad198x_patch_ops = {
-       .build_controls = ad198x_build_controls,
-       .build_pcms = ad198x_build_pcms,
-       .init = ad198x_init,
-       .free = ad198x_free,
-#ifdef CONFIG_PM
-       .check_power_status = ad198x_check_power_status,
-       .suspend = ad198x_suspend,
-#endif
-       .reboot_notify = ad198x_shutup,
-};
-
-
-/*
- * EAPD control
- * the private value = nid
- */
-#define ad198x_eapd_info       snd_ctl_boolean_mono_info
-
-static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       if (codec->inv_eapd)
-               ucontrol->value.integer.value[0] = ! spec->cur_eapd;
-       else
-               ucontrol->value.integer.value[0] = spec->cur_eapd;
-       return 0;
-}
-
-static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       hda_nid_t nid = kcontrol->private_value & 0xff;
-       unsigned int eapd;
-       eapd = !!ucontrol->value.integer.value[0];
-       if (codec->inv_eapd)
-               eapd = !eapd;
-       if (eapd == spec->cur_eapd)
-               return 0;
-       spec->cur_eapd = eapd;
-       snd_hda_codec_write_cache(codec, nid,
-                                 0, AC_VERB_SET_EAPD_BTLENABLE,
-                                 eapd ? 0x02 : 0x00);
-       return 1;
-}
-
-static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_info *uinfo);
-static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol);
-static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol);
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * Automatic parse of I/O pins from the BIOS configuration
@@ -646,580 +199,124 @@ static int ad198x_parse_auto_config(struct hda_codec *codec)
  * AD1986A specific
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-#define AD1986A_SPDIF_OUT      0x02
-#define AD1986A_FRONT_DAC      0x03
-#define AD1986A_SURR_DAC       0x04
-#define AD1986A_CLFE_DAC       0x05
-#define AD1986A_ADC            0x06
-
-static const hda_nid_t ad1986a_dac_nids[3] = {
-       AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
-};
-static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
-static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
-
-static const struct hda_input_mux ad1986a_capture_source = {
-       .num_items = 7,
-       .items = {
-               { "Mic", 0x0 },
-               { "CD", 0x1 },
-               { "Aux", 0x3 },
-               { "Line", 0x4 },
-               { "Mix", 0x5 },
-               { "Mono", 0x6 },
-               { "Phone", 0x7 },
-       },
-};
-
-
-static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+static int alloc_ad_spec(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
 
-static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+       snd_hda_gen_spec_init(&spec->gen);
+       return 0;
+}
 
 /*
- * mixers
+ * AD1986A fixup codes
  */
-static const struct snd_kcontrol_new ad1986a_mixers[] = {
-       /*
-        * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
-        */
-       HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
-       HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/* additional mixers for 3stack mode */
-static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = ad198x_ch_mode_info,
-               .get = ad198x_ch_mode_get,
-               .put = ad198x_ch_mode_put,
-       },
-       { } /* end */
-};
 
-/* laptop model - 2ch only */
-static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
+/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
+static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               codec->inv_jack_detect = 1;
+}
 
-/* master controls both pins 0x1a and 0x1b */
-static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-               0,
-       },
+enum {
+       AD1986A_FIXUP_INV_JACK_DETECT,
+       AD1986A_FIXUP_ULTRA,
+       AD1986A_FIXUP_SAMSUNG,
+       AD1986A_FIXUP_3STACK,
+       AD1986A_FIXUP_LAPTOP,
+       AD1986A_FIXUP_LAPTOP_IMIC,
 };
 
-static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-               0,
+static const struct hda_fixup ad1986a_fixups[] = {
+       [AD1986A_FIXUP_INV_JACK_DETECT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad_fixup_inv_jack_detect,
        },
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
-       /* 
-          HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
-          HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
+       [AD1986A_FIXUP_ULTRA] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1d, 0x90a7013e }, /* int mic */
+                       {}
+               },
        },
-       { } /* end */
-};
-
-/* laptop-eapd model - 2ch only */
-
-static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x4 },
-               { "Mix", 0x5 },
+       [AD1986A_FIXUP_SAMSUNG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1d, 0x90a7013e }, /* int mic */
+                       { 0x20, 0x411111f0 }, /* N/A */
+                       { 0x24, 0x411111f0 }, /* N/A */
+                       {}
+               },
        },
-};
-
-static const struct hda_input_mux ad1986a_automic_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               { "Mix", 0x5 },
+       [AD1986A_FIXUP_3STACK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x02214021 }, /* headphone */
+                       { 0x1b, 0x01014011 }, /* front */
+                       { 0x1c, 0x01013012 }, /* surround */
+                       { 0x1d, 0x01019015 }, /* clfe */
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { 0x1f, 0x02a190f0 }, /* mic */
+                       { 0x20, 0x018130f0 }, /* line-in */
+                       {}
+               },
        },
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
-       HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
+       [AD1986A_FIXUP_LAPTOP] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x02214021 }, /* headphone */
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { 0x1f, 0x02a191f0 }, /* mic */
+                       { 0x20, 0x411111f0 }, /* N/A */
+                       {}
+               },
        },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "External Amplifier",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad198x_eapd_put,
-               .private_value = 0x1b, /* port-D */
+       [AD1986A_FIXUP_LAPTOP_IMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1d, 0x90a7013e }, /* int mic */
+                       {}
+               },
+               .chained_before = 1,
+               .chain_id = AD1986A_FIXUP_LAPTOP,
        },
-       { } /* end */
 };
 
-static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
-       { } /* end */
+static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
+       SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
+       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
+       SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
+       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
+       SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
+       {}
 };
 
-/* re-connect the mic boost input according to the jack sensing */
-static void ad1986a_automic(struct hda_codec *codec)
-{
-       unsigned int present;
-       present = snd_hda_jack_detect(codec, 0x1f);
-       /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
-       snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
-                           present ? 0 : 2);
-}
-
-#define AD1986A_MIC_EVENT              0x36
-
-static void ad1986a_automic_unsol_event(struct hda_codec *codec,
-                                           unsigned int res)
-{
-       if ((res >> 26) != AD1986A_MIC_EVENT)
-               return;
-       ad1986a_automic(codec);
-}
-
-static int ad1986a_automic_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1986a_automic(codec);
-       return 0;
-}
-
-/* laptop-automute - 2ch only */
-
-static void ad1986a_update_hp(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int mute;
-
-       if (spec->jack_present)
-               mute = HDA_AMP_MUTE; /* mute internal speaker */
-       else
-               /* unmute internal speaker if necessary */
-               mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
-       snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, mute);
-}
-
-static void ad1986a_hp_automute(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
-       if (spec->inv_jack_detect)
-               spec->jack_present = !spec->jack_present;
-       ad1986a_update_hp(codec);
-}
-
-#define AD1986A_HP_EVENT               0x37
-
-static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       if ((res >> 26) != AD1986A_HP_EVENT)
-               return;
-       ad1986a_hp_automute(codec);
-}
-
-static int ad1986a_hp_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1986a_hp_automute(codec);
-       return 0;
-}
-
-/* bind hp and internal speaker mute (with plug check) */
-static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-       if (change)
-               ad1986a_update_hp(codec);
-       return change;
-}
-
-static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
-       HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = ad1986a_hp_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
-       },
-       { } /* end */
-};
-
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1986a_init_verbs[] = {
-       /* Front, Surround, CLFE DAC; mute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Downmix - off */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* HP, Line-Out, Surround, CLFE selectors */
-       {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mono selector */
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mic selector: Mic 1/2 pin */
-       {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Line-in selector: Line-in */
-       {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mic 1/2 swap */
-       {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Record selector: mic */
-       {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* PC beep */
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* HP Pin */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-       /* Front, Surround, CLFE Pins */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* Mono Pin */
-       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* Mic Pin */
-       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* Line, Aux, CD, Beep-In Pin */
-       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       { } /* end */
-};
-
-static const struct hda_verb ad1986a_ch2_init[] = {
-       /* Surround out -> Line In */
-       { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       /* Line-in selectors */
-       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
-       /* CLFE -> Mic in */
-       { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
-       { } /* end */
-};
-
-static const struct hda_verb ad1986a_ch4_init[] = {
-       /* Surround out -> Surround */
-       { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
-       /* CLFE -> Mic in */
-       { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
-       { } /* end */
-};
-
-static const struct hda_verb ad1986a_ch6_init[] = {
-       /* Surround out -> Surround out */
-       { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
-       /* CLFE -> CLFE */
-       { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode ad1986a_modes[3] = {
-       { 2, ad1986a_ch2_init },
-       { 4, ad1986a_ch4_init },
-       { 6, ad1986a_ch6_init },
-};
-
-/* eapd initialization */
-static const struct hda_verb ad1986a_eapd_init_verbs[] = {
-       {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
-       {}
-};
-
-static const struct hda_verb ad1986a_automic_verbs[] = {
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
-       {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
-       {}
-};
-
-/* Ultra initialization */
-static const struct hda_verb ad1986a_ultra_init[] = {
-       /* eapd initialization */
-       { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
-       /* CLFE -> Mic in */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
-       { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
-       { } /* end */
-};
-
-/* pin sensing on HP jack */
-static const struct hda_verb ad1986a_hp_init_verbs[] = {
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
-       {}
-};
-
-static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
-                                           unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1986A_HP_EVENT:
-               ad1986a_hp_automute(codec);
-               break;
-       case AD1986A_MIC_EVENT:
-               ad1986a_automic(codec);
-               break;
-       }
-}
-
-static int ad1986a_samsung_p50_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1986a_hp_automute(codec);
-       ad1986a_automic(codec);
-       return 0;
-}
-
-
-/* models */
-enum {
-       AD1986A_AUTO,
-       AD1986A_6STACK,
-       AD1986A_3STACK,
-       AD1986A_LAPTOP,
-       AD1986A_LAPTOP_EAPD,
-       AD1986A_LAPTOP_AUTOMUTE,
-       AD1986A_ULTRA,
-       AD1986A_SAMSUNG,
-       AD1986A_SAMSUNG_P50,
-       AD1986A_MODELS
-};
-
-static const char * const ad1986a_models[AD1986A_MODELS] = {
-       [AD1986A_AUTO]          = "auto",
-       [AD1986A_6STACK]        = "6stack",
-       [AD1986A_3STACK]        = "3stack",
-       [AD1986A_LAPTOP]        = "laptop",
-       [AD1986A_LAPTOP_EAPD]   = "laptop-eapd",
-       [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
-       [AD1986A_ULTRA]         = "ultra",
-       [AD1986A_SAMSUNG]       = "samsung",
-       [AD1986A_SAMSUNG_P50]   = "samsung-p50",
-};
-
-static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
-       SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
-       SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
-       SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
-       SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
-       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
-       SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
-       SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
-       SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
-       {}
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1986a_loopbacks[] = {
-       { 0x13, HDA_OUTPUT, 0 }, /* Mic */
-       { 0x14, HDA_OUTPUT, 0 }, /* Phone */
-       { 0x15, HDA_OUTPUT, 0 }, /* CD */
-       { 0x16, HDA_OUTPUT, 0 }, /* Aux */
-       { 0x17, HDA_OUTPUT, 0 }, /* Line */
-       { } /* end */
-};
-#endif
-
-static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
-{
-       unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
-       return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
-}
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-static int alloc_ad_spec(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-       codec->spec = spec;
-       snd_hda_gen_spec_init(&spec->gen);
-       return 0;
-}
-
-/*
- * AD1986A fixup codes
- */
-
-/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
-static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               codec->inv_jack_detect = 1;
-}
-
-enum {
-       AD1986A_FIXUP_INV_JACK_DETECT,
-};
-
-static const struct hda_fixup ad1986a_fixups[] = {
-       [AD1986A_FIXUP_INV_JACK_DETECT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad_fixup_inv_jack_detect,
-       },
-};
-
-static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
+static const struct hda_model_fixup ad1986a_fixup_models[] = {
+       { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
+       { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
+       { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
+       { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
        {}
 };
 
 /*
  */
-static int ad1986a_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1986a(struct hda_codec *codec)
 {
        int err;
        struct ad198x_spec *spec;
@@ -1244,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
         */
        spec->gen.multiout.no_share_stream = 1;
 
-       snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups);
+       snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
+                          ad1986a_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
        err = ad198x_parse_auto_config(codec);
@@ -1258,330 +356,11 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
        return 0;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1986a(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
-                                                 ad1986a_models,
-                                                 ad1986a_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1986A_AUTO;
-       }
-
-       if (board_config == AD1986A_AUTO)
-               return ad1986a_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x19);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 6;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
-       spec->multiout.dac_nids = ad1986a_dac_nids;
-       spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
-       spec->num_adc_nids = 1;
-       spec->adc_nids = ad1986a_adc_nids;
-       spec->capsrc_nids = ad1986a_capsrc_nids;
-       spec->input_mux = &ad1986a_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1986a_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1986a_init_verbs;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1986a_loopbacks;
-#endif
-       spec->vmaster_nid = 0x1b;
-       codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       /* override some parameters */
-       switch (board_config) {
-       case AD1986A_3STACK:
-               spec->num_mixers = 2;
-               spec->mixers[1] = ad1986a_3st_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1986a_ch2_init;
-               spec->channel_mode = ad1986a_modes;
-               spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
-               spec->need_dac_fix = 1;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               break;
-       case AD1986A_LAPTOP:
-               spec->mixers[0] = ad1986a_laptop_mixers;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               break;
-       case AD1986A_LAPTOP_EAPD:
-               spec->num_mixers = 3;
-               spec->mixers[0] = ad1986a_laptop_master_mixers;
-               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-               spec->mixers[2] = ad1986a_laptop_intmic_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               if (!is_jack_available(codec, 0x25))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1986a_laptop_eapd_capture_source;
-               break;
-       case AD1986A_SAMSUNG:
-               spec->num_mixers = 2;
-               spec->mixers[0] = ad1986a_laptop_master_mixers;
-               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-               spec->num_init_verbs = 3;
-               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-               spec->init_verbs[2] = ad1986a_automic_verbs;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               if (!is_jack_available(codec, 0x25))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1986a_automic_capture_source;
-               codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
-               codec->patch_ops.init = ad1986a_automic_init;
-               break;
-       case AD1986A_SAMSUNG_P50:
-               spec->num_mixers = 2;
-               spec->mixers[0] = ad1986a_automute_master_mixers;
-               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-               spec->num_init_verbs = 4;
-               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-               spec->init_verbs[2] = ad1986a_automic_verbs;
-               spec->init_verbs[3] = ad1986a_hp_init_verbs;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               if (!is_jack_available(codec, 0x25))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1986a_automic_capture_source;
-               codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
-               codec->patch_ops.init = ad1986a_samsung_p50_init;
-               break;
-       case AD1986A_LAPTOP_AUTOMUTE:
-               spec->num_mixers = 3;
-               spec->mixers[0] = ad1986a_automute_master_mixers;
-               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-               spec->mixers[2] = ad1986a_laptop_intmic_mixers;
-               spec->num_init_verbs = 3;
-               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-               spec->init_verbs[2] = ad1986a_hp_init_verbs;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               if (!is_jack_available(codec, 0x25))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1986a_laptop_eapd_capture_source;
-               codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
-               codec->patch_ops.init = ad1986a_hp_init;
-               /* Lenovo N100 seems to report the reversed bit
-                * for HP jack-sensing
-                */
-               spec->inv_jack_detect = 1;
-               break;
-       case AD1986A_ULTRA:
-               spec->mixers[0] = ad1986a_laptop_eapd_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1986a_ultra_init;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               spec->multiout.dig_out_nid = 0;
-               break;
-       }
-
-       /* AD1986A has a hardware problem that it can't share a stream
-        * with multiple output pins.  The copy of front to surrounds
-        * causes noisy or silent outputs at a certain timing, e.g.
-        * changing the volume.
-        * So, let's disable the shared stream.
-        */
-       spec->multiout.no_share_stream = 1;
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1986a  ad1986a_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 
 /*
  * AD1983 specific
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-#define AD1983_SPDIF_OUT       0x02
-#define AD1983_DAC             0x03
-#define AD1983_ADC             0x04
-
-static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
-static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
-static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
-
-static const struct hda_input_mux ad1983_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Line", 0x1 },
-               { "Mix", 0x2 },
-               { "Mix Mono", 0x3 },
-       },
-};
-
-/*
- * SPDIF playback route
- */
-static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       static const char * const texts[] = { "PCM", "ADC" };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 2;
-       if (uinfo->value.enumerated.item > 1)
-               uinfo->value.enumerated.item = 1;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->spdif_route;
-       return 0;
-}
-
-static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       if (ucontrol->value.enumerated.item[0] > 1)
-               return -EINVAL;
-       if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
-               spec->spdif_route = ucontrol->value.enumerated.item[0];
-               snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
-                                         AC_VERB_SET_CONNECT_SEL,
-                                         spec->spdif_route);
-               return 1;
-       }
-       return 0;
-}
-
-static const struct snd_kcontrol_new ad1983_mixers[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb ad1983_init_verbs[] = {
-       /* Front, HP, Mono; mute as default */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Beep, PCM, Mic, Line-In: mute */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Front, HP selectors; from Mix */
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* Mono selector; from Mix */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
-       /* Mic selector; Mic */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Line-in selector: Line-in */
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mic boost: 0dB */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       /* Record selector: mic */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* SPDIF route: PCM */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Front Pin */
-       {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* HP Pin */
-       {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-       /* Mono Pin */
-       {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* Mic Pin */
-       {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* Line Pin */
-       {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1983_loopbacks[] = {
-       { 0x12, HDA_OUTPUT, 0 }, /* Mic */
-       { 0x13, HDA_OUTPUT, 0 }, /* Line */
-       { } /* end */
-};
-#endif
-
-/* models */
-enum {
-       AD1983_AUTO,
-       AD1983_BASIC,
-       AD1983_MODELS
-};
-
-static const char * const ad1983_models[AD1983_MODELS] = {
-       [AD1983_AUTO]           = "auto",
-       [AD1983_BASIC]          = "basic",
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /*
  * SPDIF mux control for AD1983 auto-parser
  */
@@ -1656,7 +435,7 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
        return 0;
 }
 
-static int ad1983_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1983(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -1681,432 +460,11 @@ static int ad1983_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1983(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int board_config;
-       int err;
-
-       board_config = snd_hda_check_board_config(codec, AD1983_MODELS,
-                                                 ad1983_models, NULL);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1983_AUTO;
-       }
-
-       if (board_config == AD1983_AUTO)
-               return ad1983_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 2;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
-       spec->multiout.dac_nids = ad1983_dac_nids;
-       spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
-       spec->num_adc_nids = 1;
-       spec->adc_nids = ad1983_adc_nids;
-       spec->capsrc_nids = ad1983_capsrc_nids;
-       spec->input_mux = &ad1983_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1983_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1983_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1983_loopbacks;
-#endif
-       spec->vmaster_nid = 0x05;
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1983   ad1983_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * AD1981 HD specific
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-#define AD1981_SPDIF_OUT       0x02
-#define AD1981_DAC             0x03
-#define AD1981_ADC             0x04
-
-static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
-static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
-static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
-
-/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
-static const struct hda_input_mux ad1981_capture_source = {
-       .num_items = 7,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Line", 0x1 },
-               { "Mix", 0x2 },
-               { "Mix Mono", 0x3 },
-               { "CD", 0x4 },
-               { "Mic", 0x6 },
-               { "Aux", 0x7 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1981_mixers[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* identical with AD1983 */
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb ad1981_init_verbs[] = {
-       /* Front, HP, Mono; mute as default */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Front, HP selectors; from Mix */
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* Mono selector; from Mix */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
-       /* Mic Mixer; select Front Mic */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Mic boost: 0dB */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Record selector: Front mic */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* SPDIF route: PCM */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Front Pin */
-       {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* HP Pin */
-       {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-       /* Mono Pin */
-       {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* Front & Rear Mic Pins */
-       {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* Line Pin */
-       {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* Digital Beep */
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Line-Out as Input: disabled */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1981_loopbacks[] = {
-       { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
-       { 0x13, HDA_OUTPUT, 0 }, /* Line */
-       { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
-       { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
-       { 0x1d, HDA_OUTPUT, 0 }, /* CD */
-       { } /* end */
-};
-#endif
-
-/*
- * Patch for HP nx6320
- *
- * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
- * speaker output enabled _and_ mute-LED off.
- */
-
-#define AD1981_HP_EVENT                0x37
-#define AD1981_MIC_EVENT       0x38
-
-static const struct hda_verb ad1981_hp_init_verbs[] = {
-       {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
-       /* pin sensing on HP and Mic jacks */
-       {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
-       {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
-       {}
-};
-
-/* turn on/off EAPD (+ mute HP) as a master switch */
-static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       if (! ad198x_eapd_put(kcontrol, ucontrol))
-               return 0;
-       /* change speaker pin appropriately */
-       snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0);
-       /* toggle HP mute appropriately */
-       snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE,
-                                spec->cur_eapd ? 0 : HDA_AMP_MUTE);
-       return 1;
-}
-
-/* bind volumes of both NID 0x05 and 0x06 */
-static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
-/* mute internal speaker if HP is plugged */
-static void ad1981_hp_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x06);
-       snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-/* toggle input of built-in and mic jack appropriately */
-static void ad1981_hp_automic(struct hda_codec *codec)
-{
-       static const struct hda_verb mic_jack_on[] = {
-               {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-               {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-               {}
-       };
-       static const struct hda_verb mic_jack_off[] = {
-               {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-               {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-               {}
-       };
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x08);
-       if (present)
-               snd_hda_sequence_write(codec, mic_jack_on);
-       else
-               snd_hda_sequence_write(codec, mic_jack_off);
-}
-
-/* unsolicited event for HP jack sensing */
-static void ad1981_hp_unsol_event(struct hda_codec *codec,
-                                 unsigned int res)
-{
-       res >>= 26;
-       switch (res) {
-       case AD1981_HP_EVENT:
-               ad1981_hp_automute(codec);
-               break;
-       case AD1981_MIC_EVENT:
-               ad1981_hp_automic(codec);
-               break;
-       }
-}
-
-static const struct hda_input_mux ad1981_hp_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Dock Mic", 0x1 },
-               { "Mix", 0x2 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
-       HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
-               .name = "Master Playback Switch",
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad1981_hp_master_sw_put,
-               .private_value = 0x05,
-       },
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-#if 0
-       /* FIXME: analog mic/line loopback doesn't work with my tests...
-        *        (although recording is OK)
-        */
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
-       /* FIXME: does this laptop have analog CD connection? */
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-#endif
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       { } /* end */
-};
-
-/* initialize jack-sensing, too */
-static int ad1981_hp_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1981_hp_automute(codec);
-       ad1981_hp_automic(codec);
-       return 0;
-}
-
-/* configuration for Toshiba Laptops */
-static const struct hda_verb ad1981_toshiba_init_verbs[] = {
-       {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
-       /* pin sensing on HP and Mic jacks */
-       {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
-       {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
-       {}
-};
-
-static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
-       HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
-       { }
-};
-
-/* configuration for Lenovo Thinkpad T60 */
-static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* identical with AD1983 */
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_input_mux ad1981_thinkpad_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Mix", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-/* models */
-enum {
-       AD1981_AUTO,
-       AD1981_BASIC,
-       AD1981_HP,
-       AD1981_THINKPAD,
-       AD1981_TOSHIBA,
-       AD1981_MODELS
-};
-
-static const char * const ad1981_models[AD1981_MODELS] = {
-       [AD1981_AUTO]           = "auto",
-       [AD1981_HP]             = "hp",
-       [AD1981_THINKPAD]       = "thinkpad",
-       [AD1981_BASIC]          = "basic",
-       [AD1981_TOSHIBA]        = "toshiba"
-};
-
-static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
-       SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
-       /* All HP models */
-       SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
-       SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
-       /* Lenovo Thinkpad T60/X60/Z6xx */
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
-       /* HP nx6320 (reversed SSID, H/W bug) */
-       SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
-       {}
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /* follow EAPD via vmaster hook */
 static void ad_vmaster_eapd_hook(void *private_data, int enabled)
 {
@@ -2172,7 +530,7 @@ static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
        {}
 };
 
-static int ad1981_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1981(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -2205,110 +563,6 @@ static int ad1981_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1981(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
-                                                 ad1981_models,
-                                                 ad1981_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1981_AUTO;
-       }
-
-       if (board_config == AD1981_AUTO)
-               return ad1981_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return -ENOMEM;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 2;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
-       spec->multiout.dac_nids = ad1981_dac_nids;
-       spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
-       spec->num_adc_nids = 1;
-       spec->adc_nids = ad1981_adc_nids;
-       spec->capsrc_nids = ad1981_capsrc_nids;
-       spec->input_mux = &ad1981_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1981_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1981_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1981_loopbacks;
-#endif
-       spec->vmaster_nid = 0x05;
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       /* override some parameters */
-       switch (board_config) {
-       case AD1981_HP:
-               spec->mixers[0] = ad1981_hp_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1981_hp_init_verbs;
-               if (!is_jack_available(codec, 0x0a))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1981_hp_capture_source;
-
-               codec->patch_ops.init = ad1981_hp_init;
-               codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       case AD1981_THINKPAD:
-               spec->mixers[0] = ad1981_thinkpad_mixers;
-               spec->input_mux = &ad1981_thinkpad_capture_source;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       case AD1981_TOSHIBA:
-               spec->mixers[0] = ad1981_hp_mixers;
-               spec->mixers[1] = ad1981_toshiba_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1981_toshiba_init_verbs;
-               spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1981_hp_capture_source;
-               codec->patch_ops.init = ad1981_hp_init;
-               codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
-               break;
-       }
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1981   ad1981_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * AD1988
@@ -2395,90 +649,7 @@ static int patch_ad1981(struct hda_codec *codec)
  *      E/F quad mic array
  */
 
-
 #ifdef ENABLE_AD_STATIC_QUIRKS
-/* models */
-enum {
-       AD1988_AUTO,
-       AD1988_6STACK,
-       AD1988_6STACK_DIG,
-       AD1988_3STACK,
-       AD1988_3STACK_DIG,
-       AD1988_LAPTOP,
-       AD1988_LAPTOP_DIG,
-       AD1988_MODEL_LAST,
-};
-
-/* reivision id to check workarounds */
-#define AD1988A_REV2           0x100200
-
-#define is_rev2(codec) \
-       ((codec)->vendor_id == 0x11d41988 && \
-        (codec)->revision_id == AD1988A_REV2)
-
-/*
- * mixers
- */
-
-static const hda_nid_t ad1988_6stack_dac_nids[4] = {
-       0x04, 0x06, 0x05, 0x0a
-};
-
-static const hda_nid_t ad1988_3stack_dac_nids[3] = {
-       0x04, 0x05, 0x0a
-};
-
-/* for AD1988A revision-2, DAC2-4 are swapped */
-static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
-       0x04, 0x05, 0x0a, 0x06
-};
-
-static const hda_nid_t ad1988_alt_dac_nid[1] = {
-       0x03
-};
-
-static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
-       0x04, 0x0a, 0x06
-};
-
-static const hda_nid_t ad1988_adc_nids[3] = {
-       0x08, 0x09, 0x0f
-};
-
-static const hda_nid_t ad1988_capsrc_nids[3] = {
-       0x0c, 0x0d, 0x0e
-};
-
-#define AD1988_SPDIF_OUT               0x02
-#define AD1988_SPDIF_OUT_HDMI  0x0b
-#define AD1988_SPDIF_IN                0x07
-
-static const hda_nid_t ad1989b_slave_dig_outs[] = {
-       AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
-};
-
-static const struct hda_input_mux ad1988_6stack_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Front Mic", 0x1 },   /* port-B */
-               { "Line", 0x2 },        /* port-C */
-               { "Mic", 0x4 },         /* port-E */
-               { "CD", 0x5 },
-               { "Mix", 0x9 },
-       },
-};
-
-static const struct hda_input_mux ad1988_laptop_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic/Line", 0x1 },    /* port-B */
-               { "CD", 0x5 },
-               { "Mix", 0x9 },
-       },
-};
-
-/*
- */
 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_info *uinfo)
 {
@@ -2509,636 +680,73 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
                spec->multiout.num_dacs = spec->multiout.max_channels / 2;
        return err;
 }
+#endif /* ENABLE_AD_STATIC_QUIRKS */
 
-/* 6-stack mode */
-static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/* 3-stack mode */
-static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = ad198x_ch_mode_info,
-               .get = ad198x_ch_mode_get,
-               .put = ad198x_ch_mode_put,
-       },
-
-       { } /* end */
-};
-
-/* laptop mode */
-static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
-       HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "External Amplifier",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad198x_eapd_put,
-               .private_value = 0x12, /* port-D */
-       },
-
-       { } /* end */
-};
-
-/* capture */
-static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 3,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
-                                            struct snd_ctl_elem_info *uinfo)
+static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_info *uinfo)
 {
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        static const char * const texts[] = {
-               "PCM", "ADC1", "ADC2", "ADC3"
+               "PCM", "ADC1", "ADC2", "ADC3",
        };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 4;
-       if (uinfo->value.enumerated.item >= 4)
-               uinfo->value.enumerated.item = 3;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
+       int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
+       if (num_conns > 4)
+               num_conns = 4;
+       return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
 }
 
-static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
-                                           struct snd_ctl_elem_value *ucontrol)
+static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int sel;
-
-       sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
-                                AC_AMP_GET_INPUT);
-       if (!(sel & 0x80))
-               ucontrol->value.enumerated.item[0] = 0;
-       else {
-               sel = snd_hda_codec_read(codec, 0x0b, 0,
-                                        AC_VERB_GET_CONNECT_SEL, 0);
-               if (sel < 3)
-                       sel++;
-               else
-                       sel = 0;
-               ucontrol->value.enumerated.item[0] = sel;
-       }
+       struct ad198x_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->cur_smux;
        return 0;
 }
 
-static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
-                                           struct snd_ctl_elem_value *ucontrol)
+static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int val, sel;
-       int change;
+       struct ad198x_spec *spec = codec->spec;
+       unsigned int val = ucontrol->value.enumerated.item[0];
+       struct nid_path *path;
+       int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
 
-       val = ucontrol->value.enumerated.item[0];
-       if (val > 3)
+       if (val >= num_conns)
                return -EINVAL;
-       if (!val) {
-               sel = snd_hda_codec_read(codec, 0x1d, 0,
-                                        AC_VERB_GET_AMP_GAIN_MUTE,
-                                        AC_AMP_GET_INPUT);
-               change = sel & 0x80;
-               if (change) {
-                       snd_hda_codec_write_cache(codec, 0x1d, 0,
-                                                 AC_VERB_SET_AMP_GAIN_MUTE,
-                                                 AMP_IN_UNMUTE(0));
-                       snd_hda_codec_write_cache(codec, 0x1d, 0,
-                                                 AC_VERB_SET_AMP_GAIN_MUTE,
-                                                 AMP_IN_MUTE(1));
-               }
-       } else {
-               sel = snd_hda_codec_read(codec, 0x1d, 0,
-                                        AC_VERB_GET_AMP_GAIN_MUTE,
-                                        AC_AMP_GET_INPUT | 0x01);
-               change = sel & 0x80;
-               if (change) {
-                       snd_hda_codec_write_cache(codec, 0x1d, 0,
-                                                 AC_VERB_SET_AMP_GAIN_MUTE,
-                                                 AMP_IN_MUTE(0));
-                       snd_hda_codec_write_cache(codec, 0x1d, 0,
-                                                 AC_VERB_SET_AMP_GAIN_MUTE,
-                                                 AMP_IN_UNMUTE(1));
-               }
-               sel = snd_hda_codec_read(codec, 0x0b, 0,
-                                        AC_VERB_GET_CONNECT_SEL, 0) + 1;
-               change |= sel != val;
-               if (change)
-                       snd_hda_codec_write_cache(codec, 0x0b, 0,
-                                                 AC_VERB_SET_CONNECT_SEL,
-                                                 val - 1);
-       }
-       return change;
-}
+       if (spec->cur_smux == val)
+               return 0;
 
-static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "IEC958 Playback Source",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
-               .info = ad1988_spdif_playback_source_info,
-               .get = ad1988_spdif_playback_source_get,
-               .put = ad1988_spdif_playback_source_put,
-       },
-       { } /* end */
-};
+       mutex_lock(&codec->control_mutex);
+       codec->cached_write = 1;
+       path = snd_hda_get_path_from_idx(codec,
+                                        spec->smux_paths[spec->cur_smux]);
+       if (path)
+               snd_hda_activate_path(codec, path, false, true);
+       path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
+       if (path)
+               snd_hda_activate_path(codec, path, true, true);
+       spec->cur_smux = val;
+       codec->cached_write = 0;
+       mutex_unlock(&codec->control_mutex);
+       snd_hda_codec_flush_cache(codec); /* flush the updates */
+       return 1;
+}
 
-static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
-       HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
-       { } /* end */
+static struct snd_kcontrol_new ad1988_auto_smux_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Playback Source",
+       .info = ad1988_auto_smux_enum_info,
+       .get = ad1988_auto_smux_enum_get,
+       .put = ad1988_auto_smux_enum_put,
 };
 
-static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/*
- * initialization verbs
- */
-
-/*
- * for 6-stack (+dig)
- */
-static const struct hda_verb ad1988_6stack_init_verbs[] = {
-       /* Front, Surround, CLFE, side DAC; unmute as default */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-A front headphon path */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Port-D line-out path */
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Port-F surround path */
-       {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Port-G CLFE path */
-       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Port-H side path */
-       {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Mono out path */
-       {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
-       /* Port-B front mic-in path */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-C line-in path */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Port-E mic-in path */
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Analog CD Input */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-
-       { }
-};
-
-static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
-       /* Headphone; unmute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-A front headphon path */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
-       { }
-};
-
-static const struct hda_verb ad1988_capture_init_verbs[] = {
-       /* mute analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* select ADCs - front-mic */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-
-       { }
-};
-
-static const struct hda_verb ad1988_spdif_init_verbs[] = {
-       /* SPDIF out sel */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* SPDIF out pin */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-
-       { }
-};
-
-static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
-       /* unmute SPDIF input pin */
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { }
-};
-
-/* AD1989 has no ADC -> SPDIF route */
-static const struct hda_verb ad1989_spdif_init_verbs[] = {
-       /* SPDIF-1 out pin */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       /* SPDIF-2/HDMI out pin */
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       { }
-};
-
-/*
- * verbs for 3stack (+dig)
- */
-static const struct hda_verb ad1988_3stack_ch2_init[] = {
-       /* set port-C to line-in */
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       /* set port-E to mic-in */
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { } /* end */
-};
-
-static const struct hda_verb ad1988_3stack_ch6_init[] = {
-       /* set port-C to surround out */
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       /* set port-E to CLFE out */
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { } /* end */
-};
-
-static const struct hda_channel_mode ad1988_3stack_modes[2] = {
-       { 2, ad1988_3stack_ch2_init },
-       { 6, ad1988_3stack_ch6_init },
-};
-
-static const struct hda_verb ad1988_3stack_init_verbs[] = {
-       /* Front, Surround, CLFE, side DAC; unmute as default */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-A front headphon path */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Port-D line-out path */
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Mono out path */
-       {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
-       /* Port-B front mic-in path */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-C line-in/surround path - 6ch mode as default */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
-       {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Port-E mic-in/CLFE path - 6ch mode as default */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
-       {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* mute analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* select ADCs - front-mic */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-       { }
-};
-
-/*
- * verbs for laptop mode (+dig)
- */
-static const struct hda_verb ad1988_laptop_hp_on[] = {
-       /* unmute port-A and mute port-D */
-       { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-static const struct hda_verb ad1988_laptop_hp_off[] = {
-       /* mute port-A and unmute port-D */
-       { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { } /* end */
-};
-
-#define AD1988_HP_EVENT        0x01
-
-static const struct hda_verb ad1988_laptop_init_verbs[] = {
-       /* Front, Surround, CLFE, side DAC; unmute as default */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-A front headphon path */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
-       /* Port-D line-out path + EAPD */
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
-       /* Mono out path */
-       {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
-       /* Port-B mic-in path */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-C docking station - try to output */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* mute analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* select ADCs - mic */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-       { }
-};
-
-static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       if ((res >> 26) != AD1988_HP_EVENT)
-               return;
-       if (snd_hda_jack_detect(codec, 0x11))
-               snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
-       else
-               snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
-} 
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1988_loopbacks[] = {
-       { 0x20, HDA_INPUT, 0 }, /* Front Mic */
-       { 0x20, HDA_INPUT, 1 }, /* Line */
-       { 0x20, HDA_INPUT, 4 }, /* Mic */
-       { 0x20, HDA_INPUT, 6 }, /* CD */
-       { } /* end */
-};
-#endif
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
-                                     struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       static const char * const texts[] = {
-               "PCM", "ADC1", "ADC2", "ADC3",
-       };
-       int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
-       if (num_conns > 4)
-               num_conns = 4;
-       return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
-}
-
-static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->cur_smux;
-       return 0;
-}
-
-static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int val = ucontrol->value.enumerated.item[0];
-       struct nid_path *path;
-       int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
-
-       if (val >= num_conns)
-               return -EINVAL;
-       if (spec->cur_smux == val)
-               return 0;
-
-       mutex_lock(&codec->control_mutex);
-       codec->cached_write = 1;
-       path = snd_hda_get_path_from_idx(codec,
-                                        spec->smux_paths[spec->cur_smux]);
-       if (path)
-               snd_hda_activate_path(codec, path, false, true);
-       path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
-       if (path)
-               snd_hda_activate_path(codec, path, true, true);
-       spec->cur_smux = val;
-       codec->cached_write = 0;
-       mutex_unlock(&codec->control_mutex);
-       snd_hda_codec_flush_cache(codec); /* flush the updates */
-       return 1;
-}
-
-static struct snd_kcontrol_new ad1988_auto_smux_mixer = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Playback Source",
-       .info = ad1988_auto_smux_enum_info,
-       .get = ad1988_auto_smux_enum_get,
-       .put = ad1988_auto_smux_enum_put,
-};
-
-static int ad1988_auto_init(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       int i, err;
+static int ad1988_auto_init(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec = codec->spec;
+       int i, err;
 
        err = snd_hda_gen_init(codec);
        if (err < 0)
@@ -3220,7 +828,34 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
 /*
  */
 
-static int ad1988_parse_auto_config(struct hda_codec *codec)
+enum {
+       AD1988_FIXUP_6STACK_DIG,
+};
+
+static const struct hda_fixup ad1988_fixups[] = {
+       [AD1988_FIXUP_6STACK_DIG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x11, 0x02214130 }, /* front-hp */
+                       { 0x12, 0x01014010 }, /* line-out */
+                       { 0x14, 0x02a19122 }, /* front-mic */
+                       { 0x15, 0x01813021 }, /* line-in */
+                       { 0x16, 0x01011012 }, /* line-out */
+                       { 0x17, 0x01a19020 }, /* mic */
+                       { 0x1b, 0x0145f1f0 }, /* SPDIF */
+                       { 0x24, 0x01016011 }, /* line-out */
+                       { 0x25, 0x01012013 }, /* line-out */
+                       { }
+               }
+       },
+};
+
+static const struct hda_model_fixup ad1988_fixup_models[] = {
+       { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
+       {}
+};
+
+static int patch_ad1988(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -3234,12 +869,19 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
        spec->gen.mixer_merge_nid = 0x21;
        spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
+       snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
        err = ad198x_parse_auto_config(codec);
        if (err < 0)
                goto error;
        err = ad1988_add_spdif_mux_ctl(codec);
        if (err < 0)
                goto error;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
        return 0;
 
  error:
@@ -3247,169 +889,6 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-/*
- */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const char * const ad1988_models[AD1988_MODEL_LAST] = {
-       [AD1988_6STACK]         = "6stack",
-       [AD1988_6STACK_DIG]     = "6stack-dig",
-       [AD1988_3STACK]         = "3stack",
-       [AD1988_3STACK_DIG]     = "3stack-dig",
-       [AD1988_LAPTOP]         = "laptop",
-       [AD1988_LAPTOP_DIG]     = "laptop-dig",
-       [AD1988_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
-       SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
-       SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
-       {}
-};
-
-static int patch_ad1988(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
-                                                 ad1988_models, ad1988_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1988_AUTO;
-       }
-
-       if (board_config == AD1988_AUTO)
-               return ad1988_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       if (is_rev2(codec))
-               snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       if (!spec->multiout.hp_nid)
-               spec->multiout.hp_nid = ad1988_alt_dac_nid[0];
-       switch (board_config) {
-       case AD1988_6STACK:
-       case AD1988_6STACK_DIG:
-               spec->multiout.max_channels = 8;
-               spec->multiout.num_dacs = 4;
-               if (is_rev2(codec))
-                       spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
-               else
-                       spec->multiout.dac_nids = ad1988_6stack_dac_nids;
-               spec->input_mux = &ad1988_6stack_capture_source;
-               spec->num_mixers = 2;
-               if (is_rev2(codec))
-                       spec->mixers[0] = ad1988_6stack_mixers1_rev2;
-               else
-                       spec->mixers[0] = ad1988_6stack_mixers1;
-               spec->mixers[1] = ad1988_6stack_mixers2;
-               spec->num_init_verbs = 1;
-               spec->init_verbs[0] = ad1988_6stack_init_verbs;
-               if (board_config == AD1988_6STACK_DIG) {
-                       spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
-                       spec->dig_in_nid = AD1988_SPDIF_IN;
-               }
-               break;
-       case AD1988_3STACK:
-       case AD1988_3STACK_DIG:
-               spec->multiout.max_channels = 6;
-               spec->multiout.num_dacs = 3;
-               if (is_rev2(codec))
-                       spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
-               else
-                       spec->multiout.dac_nids = ad1988_3stack_dac_nids;
-               spec->input_mux = &ad1988_6stack_capture_source;
-               spec->channel_mode = ad1988_3stack_modes;
-               spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
-               spec->num_mixers = 2;
-               if (is_rev2(codec))
-                       spec->mixers[0] = ad1988_3stack_mixers1_rev2;
-               else
-                       spec->mixers[0] = ad1988_3stack_mixers1;
-               spec->mixers[1] = ad1988_3stack_mixers2;
-               spec->num_init_verbs = 1;
-               spec->init_verbs[0] = ad1988_3stack_init_verbs;
-               if (board_config == AD1988_3STACK_DIG)
-                       spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
-               break;
-       case AD1988_LAPTOP:
-       case AD1988_LAPTOP_DIG:
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1988_3stack_dac_nids;
-               spec->input_mux = &ad1988_laptop_capture_source;
-               spec->num_mixers = 1;
-               spec->mixers[0] = ad1988_laptop_mixers;
-               codec->inv_eapd = 1; /* inverted EAPD */
-               spec->num_init_verbs = 1;
-               spec->init_verbs[0] = ad1988_laptop_init_verbs;
-               if (board_config == AD1988_LAPTOP_DIG)
-                       spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
-               break;
-       }
-
-       spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
-       spec->adc_nids = ad1988_adc_nids;
-       spec->capsrc_nids = ad1988_capsrc_nids;
-       spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
-       spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
-       if (spec->multiout.dig_out_nid) {
-               if (codec->vendor_id >= 0x11d4989a) {
-                       spec->mixers[spec->num_mixers++] =
-                               ad1989_spdif_out_mixers;
-                       spec->init_verbs[spec->num_init_verbs++] =
-                               ad1989_spdif_init_verbs;
-                       codec->slave_dig_outs = ad1989b_slave_dig_outs;
-               } else {
-                       spec->mixers[spec->num_mixers++] =
-                               ad1988_spdif_out_mixers;
-                       spec->init_verbs[spec->num_init_verbs++] =
-                               ad1988_spdif_init_verbs;
-               }
-       }
-       if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
-               spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
-               spec->init_verbs[spec->num_init_verbs++] =
-                       ad1988_spdif_in_init_verbs;
-       }
-
-       codec->patch_ops = ad198x_patch_ops;
-       switch (board_config) {
-       case AD1988_LAPTOP:
-       case AD1988_LAPTOP_DIG:
-               codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
-               break;
-       }
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1988_loopbacks;
-#endif
-       spec->vmaster_nid = 0x04;
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1988   ad1988_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * AD1884 / AD1984
@@ -3423,167 +902,19 @@ static int patch_ad1988(struct hda_codec *codec)
  *
  * AD1984 = AD1884 + two digital mic-ins
  *
- * FIXME:
- * For simplicity, we share the single DAC for both HP and line-outs
- * right now.  The inidividual playbacks could be easily implemented,
- * but no build-up framework is given, so far.
- */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const hda_nid_t ad1884_dac_nids[1] = {
-       0x04,
-};
-
-static const hda_nid_t ad1884_adc_nids[2] = {
-       0x08, 0x09,
-};
-
-static const hda_nid_t ad1884_capsrc_nids[2] = {
-       0x0c, 0x0d,
-};
-
-#define AD1884_SPDIF_OUT       0x02
-
-static const struct hda_input_mux ad1884_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Mic", 0x1 },
-               { "CD", 0x2 },
-               { "Mix", 0x3 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1884_base_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* SPDIF controls */
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               /* identical with ad1983 */
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
-       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
-                            HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
-                          HDA_INPUT),
-       { } /* end */
-};
-
-/*
- * initialization verbs
+ * AD1883 / AD1884A / AD1984A / AD1984B
+ *
+ * port-B (0x14) - front mic-in
+ * port-E (0x1c) - rear mic-in
+ * port-F (0x16) - CD / ext out
+ * port-C (0x15) - rear line-in
+ * port-D (0x12) - rear line-out
+ * port-A (0x11) - front hp-out
+ *
+ * AD1984A = AD1884A + digital-mic
+ * AD1883 = equivalent with AD1984A
+ * AD1984B = AD1984A + extra SPDIF-out
  */
-static const struct hda_verb ad1884_init_verbs[] = {
-       /* DACs; mute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-A (HP) mixer */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* HP selector - select DAC2 */
-       {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Port-D (Line-out) mixer */
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-D pin */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mono-out mixer */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Mono-out pin */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mono selector */
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Port-B (front mic) pin */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Port-C (rear mic) pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-       /* SPDIF output selector */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1884_loopbacks[] = {
-       { 0x20, HDA_INPUT, 0 }, /* Front Mic */
-       { 0x20, HDA_INPUT, 1 }, /* Mic */
-       { 0x20, HDA_INPUT, 2 }, /* CD */
-       { 0x20, HDA_INPUT, 4 }, /* Docking */
-       { } /* end */
-};
-#endif
-
-static const char * const ad1884_slave_vols[] = {
-       "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
-       "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958",
-       NULL
-};
-
-enum {
-       AD1884_AUTO,
-       AD1884_BASIC,
-       AD1884_MODELS
-};
-
-static const char * const ad1884_models[AD1884_MODELS] = {
-       [AD1884_AUTO]           = "auto",
-       [AD1884_BASIC]          = "basic",
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /* set the upper-limit for mixer amp to 0dB for avoiding the possible
  * damage by overloading
@@ -3599,14 +930,34 @@ static void ad1884_fixup_amp_override(struct hda_codec *codec,
                                          (1 << AC_AMPCAP_MUTE_SHIFT));
 }
 
+/* toggle GPIO1 according to the mute state */
+static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct ad198x_spec *spec = codec->spec;
+
+       if (spec->eapd_nid)
+               ad_vmaster_eapd_hook(private_data, enabled);
+       snd_hda_codec_update_cache(codec, 0x01, 0,
+                                  AC_VERB_SET_GPIO_DATA,
+                                  enabled ? 0x00 : 0x02);
+}
+
 static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
                                 const struct hda_fixup *fix, int action)
 {
        struct ad198x_spec *spec = codec->spec;
+       static const struct hda_verb gpio_init_verbs[] = {
+               {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
+               {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
+               {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
+               {},
+       };
 
        switch (action) {
        case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+               spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
+               snd_hda_sequence_write_cache(codec, gpio_init_verbs);
                break;
        case HDA_FIXUP_ACT_PROBE:
                if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
@@ -3617,9 +968,18 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
        }
 }
 
+/* set magic COEFs for dmic */
+static const struct hda_verb ad1884_dmic_init_verbs[] = {
+       {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
+       {0x01, AC_VERB_SET_PROC_COEF, 0x08},
+       {}
+};
+
 enum {
        AD1884_FIXUP_AMP_OVERRIDE,
        AD1884_FIXUP_HP_EAPD,
+       AD1884_FIXUP_DMIC_COEF,
+       AD1884_FIXUP_HP_TOUCHSMART,
 };
 
 static const struct hda_fixup ad1884_fixups[] = {
@@ -3633,15 +993,27 @@ static const struct hda_fixup ad1884_fixups[] = {
                .chained = true,
                .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
        },
+       [AD1884_FIXUP_DMIC_COEF] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = ad1884_dmic_init_verbs,
+       },
+       [AD1884_FIXUP_HP_TOUCHSMART] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = ad1884_dmic_init_verbs,
+               .chained = true,
+               .chain_id = AD1884_FIXUP_HP_EAPD,
+       },
 };
 
 static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
        SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF),
        {}
 };
 
 
-static int ad1884_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1884(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -3674,1170 +1046,6 @@ static int ad1884_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1884_basic(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err;
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 2;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
-       spec->multiout.dac_nids = ad1884_dac_nids;
-       spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
-       spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
-       spec->adc_nids = ad1884_adc_nids;
-       spec->capsrc_nids = ad1884_capsrc_nids;
-       spec->input_mux = &ad1884_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1884_base_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1884_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1884_loopbacks;
-#endif
-       spec->vmaster_nid = 0x04;
-       /* we need to cover all playback volumes */
-       spec->slave_vols = ad1884_slave_vols;
-       /* slaves may contain input volumes, so we can't raise to 0dB blindly */
-       spec->avoid_init_slave_vol = 1;
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-
-static int patch_ad1884(struct hda_codec *codec)
-{
-       int board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1884_MODELS,
-                                                 ad1884_models, NULL);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1884_AUTO;
-       }
-
-       if (board_config == AD1884_AUTO)
-               return ad1884_parse_auto_config(codec);
-       else
-               return patch_ad1884_basic(codec);
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1884   ad1884_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-/*
- * Lenovo Thinkpad T61/X61
- */
-static const struct hda_input_mux ad1984_thinkpad_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-               { "Mix", 0x3 },
-               { "Dock Mic", 0x4 },
-       },
-};
-
-
-/*
- * Dell Precision T3400
- */
-static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Line-In", 0x1 },
-               { "Mix", 0x3 },
-       },
-};
-
-
-static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* SPDIF controls */
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               /* identical with ad1983 */
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-/* additional verbs */
-static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
-       /* Port-E (docking station mic) pin */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* docking mic boost */
-       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Analog PC Beeper - allow firmware/ACPI beeps */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
-       /* Analog mixer - docking mic; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* enable EAPD bit */
-       {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-       { } /* end */
-};
-
-/*
- * Dell Precision T3400
- */
-static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       { } /* end */
-};
-
-/* Digial MIC ADC NID 0x05 + 0x06 */
-static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  unsigned int stream_tag,
-                                  unsigned int format,
-                                  struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
-                                  stream_tag, 0, format);
-       return 0;
-}
-
-static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
-       return 0;
-}
-
-static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x05,
-       .ops = {
-               .prepare = ad1984_pcm_dmic_prepare,
-               .cleanup = ad1984_pcm_dmic_cleanup
-       },
-};
-
-static int ad1984_build_pcms(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       struct hda_pcm *info;
-       int err;
-
-       err = ad198x_build_pcms(codec);
-       if (err < 0)
-               return err;
-
-       info = spec->pcm_rec + codec->num_pcms;
-       codec->num_pcms++;
-       info->name = "AD1984 Digital Mic";
-       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
-       return 0;
-}
-
-/* models */
-enum {
-       AD1984_AUTO,
-       AD1984_BASIC,
-       AD1984_THINKPAD,
-       AD1984_DELL_DESKTOP,
-       AD1984_MODELS
-};
-
-static const char * const ad1984_models[AD1984_MODELS] = {
-       [AD1984_AUTO]           = "auto",
-       [AD1984_BASIC]          = "basic",
-       [AD1984_THINKPAD]       = "thinkpad",
-       [AD1984_DELL_DESKTOP]   = "dell_desktop",
-};
-
-static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
-       /* Lenovo Thinkpad T61/X61 */
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
-       SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
-       SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
-       {}
-};
-
-static int patch_ad1984(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int board_config, err;
-
-       board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
-                                                 ad1984_models, ad1984_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1984_AUTO;
-       }
-
-       if (board_config == AD1984_AUTO)
-               return ad1884_parse_auto_config(codec);
-
-       err = patch_ad1884_basic(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       switch (board_config) {
-       case AD1984_BASIC:
-               /* additional digital mics */
-               spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
-               codec->patch_ops.build_pcms = ad1984_build_pcms;
-               break;
-       case AD1984_THINKPAD:
-               if (codec->subsystem_id == 0x17aa20fb) {
-                       /* Thinpad X300 does not have the ability to do SPDIF,
-                          or attach to docking station to use SPDIF */
-                       spec->multiout.dig_out_nid = 0;
-               } else
-                       spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
-               spec->input_mux = &ad1984_thinkpad_capture_source;
-               spec->mixers[0] = ad1984_thinkpad_mixers;
-               spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
-               spec->analog_beep = 1;
-               break;
-       case AD1984_DELL_DESKTOP:
-               spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1984_dell_desktop_capture_source;
-               spec->mixers[0] = ad1984_dell_desktop_mixers;
-               break;
-       }
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1984   ad1884_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
-/*
- * AD1883 / AD1884A / AD1984A / AD1984B
- *
- * port-B (0x14) - front mic-in
- * port-E (0x1c) - rear mic-in
- * port-F (0x16) - CD / ext out
- * port-C (0x15) - rear line-in
- * port-D (0x12) - rear line-out
- * port-A (0x11) - front hp-out
- *
- * AD1984A = AD1884A + digital-mic
- * AD1883 = equivalent with AD1984A
- * AD1984B = AD1984A + extra SPDIF-out
- *
- * FIXME:
- * We share the single DAC for both HP and line-outs (see AD1884/1984).
- */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const hda_nid_t ad1884a_dac_nids[1] = {
-       0x03,
-};
-
-#define ad1884a_adc_nids       ad1884_adc_nids
-#define ad1884a_capsrc_nids    ad1884_capsrc_nids
-
-#define AD1884A_SPDIF_OUT      0x02
-
-static const struct hda_input_mux ad1884a_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Mic", 0x4 },
-               { "Line", 0x1 },
-               { "CD", 0x2 },
-               { "Mix", 0x3 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* SPDIF controls */
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               /* identical with ad1983 */
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1884a_init_verbs[] = {
-       /* DACs; unmute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       /* Port-A (HP) mixer - route only from analog mixer */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Port-D (Line-out) mixer - route only from analog mixer */
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-D pin */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mono-out mixer - route only from analog mixer */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Mono-out pin */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Port-B (front mic) pin */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Port-C (rear line-in) pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Port-E (rear mic) pin */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
-       /* Port-F (CD) pin */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* capture sources */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* SPDIF output amp */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1884a_loopbacks[] = {
-       { 0x20, HDA_INPUT, 0 }, /* Front Mic */
-       { 0x20, HDA_INPUT, 1 }, /* Mic */
-       { 0x20, HDA_INPUT, 2 }, /* CD */
-       { 0x20, HDA_INPUT, 4 }, /* Docking */
-       { } /* end */
-};
-#endif
-
-/*
- * Laptop model
- *
- * Port A: Headphone jack
- * Port B: MIC jack
- * Port C: Internal MIC
- * Port D: Dock Line Out (if enabled)
- * Port E: Dock Line In (if enabled)
- * Port F: Internal speakers
- */
-
-static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
-                                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-       int mute = (!ucontrol->value.integer.value[0] &&
-                   !ucontrol->value.integer.value[1]);
-       /* toggle GPIO1 according to the mute state */
-       snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                           mute ? 0x02 : 0x0);
-       return ret;
-}
-
-static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = ad1884a_mobile_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-       },
-       HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = ad1884a_mobile_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-       },
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/* mute internal speaker if HP is plugged */
-static void ad1884a_hp_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x11);
-       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
-                           present ? 0x00 : 0x02);
-}
-
-/* switch to external mic if plugged */
-static void ad1884a_hp_automic(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x14);
-       snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
-                           present ? 0 : 1);
-}
-
-#define AD1884A_HP_EVENT               0x37
-#define AD1884A_MIC_EVENT              0x36
-
-/* unsolicited event for HP jack sensing */
-static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1884A_HP_EVENT:
-               ad1884a_hp_automute(codec);
-               break;
-       case AD1884A_MIC_EVENT:
-               ad1884a_hp_automic(codec);
-               break;
-       }
-}
-
-/* initialize jack-sensing, too */
-static int ad1884a_hp_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1884a_hp_automute(codec);
-       ad1884a_hp_automic(codec);
-       return 0;
-}
-
-/* mute internal speaker if HP or docking HP is plugged */
-static void ad1884a_laptop_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x11);
-       if (!present)
-               present = snd_hda_jack_detect(codec, 0x12);
-       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
-                           present ? 0x00 : 0x02);
-}
-
-/* switch to external mic if plugged */
-static void ad1884a_laptop_automic(struct hda_codec *codec)
-{
-       unsigned int idx;
-
-       if (snd_hda_jack_detect(codec, 0x14))
-               idx = 0;
-       else if (snd_hda_jack_detect(codec, 0x1c))
-               idx = 4;
-       else
-               idx = 1;
-       snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
-}
-
-/* unsolicited event for HP jack sensing */
-static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1884A_HP_EVENT:
-               ad1884a_laptop_automute(codec);
-               break;
-       case AD1884A_MIC_EVENT:
-               ad1884a_laptop_automic(codec);
-               break;
-       }
-}
-
-/* initialize jack-sensing, too */
-static int ad1884a_laptop_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1884a_laptop_automute(codec);
-       ad1884a_laptop_automic(codec);
-       return 0;
-}
-
-/* additional verbs for laptop model */
-static const struct hda_verb ad1884a_laptop_verbs[] = {
-       /* Port-A (HP) pin - always unmuted */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-F (int speaker) mixer - route only from analog mixer */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-F (int speaker) pin */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* required for compaq 6530s/6531s speaker output */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Port-C pin - internal mic-in */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       /* Port-D (docking line-out) pin - default unmuted */
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-       /* allow to touch GPIO1 (for mute control) */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
-       { } /* end */
-};
-
-static const struct hda_verb ad1884a_mobile_verbs[] = {
-       /* DACs; unmute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       /* Port-A (HP) mixer - route only from analog mixer */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Port-A (HP) pin - always unmuted */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-B (mic jack) pin */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       /* Port-C (int mic) pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       /* Port-F (int speaker) mixer - route only from analog mixer */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-F pin */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* capture sources */
-       /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-       /* allow to touch GPIO1 (for mute control) */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
-       { } /* end */
-};
-
-/*
- * Thinkpad X300
- * 0x11 - HP
- * 0x12 - speaker
- * 0x14 - mic-in
- * 0x17 - built-in mic
- */
-
-static const struct hda_verb ad1984a_thinkpad_verbs[] = {
-       /* HP unmute */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* turn on EAPD */
-       {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       /* internal mic - dmic */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* set magic COEFs for dmic */
-       {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
-       {0x01, AC_VERB_SET_PROC_COEF, 0x08},
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x5 },
-               { "Mix", 0x3 },
-       },
-};
-
-/* mute internal speaker if HP is plugged */
-static void ad1984a_thinkpad_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x11);
-       snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-/* unsolicited event for HP jack sensing */
-static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
-                                        unsigned int res)
-{
-       if ((res >> 26) != AD1884A_HP_EVENT)
-               return;
-       ad1984a_thinkpad_automute(codec);
-}
-
-/* initialize jack-sensing, too */
-static int ad1984a_thinkpad_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1984a_thinkpad_automute(codec);
-       return 0;
-}
-
-/*
- * Precision R5500
- * 0x12 - HP/line-out
- * 0x13 - speaker (mono)
- * 0x15 - mic-in
- */
-
-static const struct hda_verb ad1984a_precision_verbs[] = {
-       /* Unmute main output path */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Select mic as input */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */
-       /* Configure as mic */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       /* HP unmute */
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* turn on EAPD */
-       {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-       /* unsolicited event for pin-sense */
-       {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-
-/* mute internal speaker if HP is plugged */
-static void ad1984a_precision_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x12);
-       snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-
-/* unsolicited event for HP jack sensing */
-static void ad1984a_precision_unsol_event(struct hda_codec *codec,
-                                        unsigned int res)
-{
-       if ((res >> 26) != AD1884A_HP_EVENT)
-               return;
-       ad1984a_precision_automute(codec);
-}
-
-/* initialize jack-sensing, too */
-static int ad1984a_precision_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1984a_precision_automute(codec);
-       return 0;
-}
-
-
-/*
- * HP Touchsmart
- * port-A (0x11)      - front hp-out
- * port-B (0x14)      - unused
- * port-C (0x15)      - unused
- * port-D (0x12)      - rear line out
- * port-E (0x1c)      - front mic-in
- * port-F (0x16)      - Internal speakers
- * digital-mic (0x17) - Internal mic
- */
-
-static const struct hda_verb ad1984a_touchsmart_verbs[] = {
-       /* DACs; unmute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       /* Port-A (HP) mixer - route only from analog mixer */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Port-A (HP) pin - always unmuted */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-E (int speaker) mixer - route only from analog mixer */
-       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
-       /* Port-E pin */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       /* Port-F (int speaker) mixer - route only from analog mixer */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-F pin */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* capture sources */
-       /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-       /* allow to touch GPIO1 (for mute control) */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
-       /* internal mic - dmic */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* set magic COEFs for dmic */
-       {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
-       {0x01, AC_VERB_SET_PROC_COEF, 0x08},
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-/*     HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .name = "Master Playback Switch",
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = ad1884a_mobile_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-       },
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-/* switch to external mic if plugged */
-static void ad1984a_touchsmart_automic(struct hda_codec *codec)
-{
-       if (snd_hda_jack_detect(codec, 0x1c))
-               snd_hda_codec_write(codec, 0x0c, 0,
-                                    AC_VERB_SET_CONNECT_SEL, 0x4);
-       else
-               snd_hda_codec_write(codec, 0x0c, 0,
-                                    AC_VERB_SET_CONNECT_SEL, 0x5);
-}
-
-
-/* unsolicited event for HP jack sensing */
-static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
-       unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1884A_HP_EVENT:
-               ad1884a_hp_automute(codec);
-               break;
-       case AD1884A_MIC_EVENT:
-               ad1984a_touchsmart_automic(codec);
-               break;
-       }
-}
-
-/* initialize jack-sensing, too */
-static int ad1984a_touchsmart_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1884a_hp_automute(codec);
-       ad1984a_touchsmart_automic(codec);
-       return 0;
-}
-
-
-/*
- */
-
-enum {
-       AD1884A_AUTO,
-       AD1884A_DESKTOP,
-       AD1884A_LAPTOP,
-       AD1884A_MOBILE,
-       AD1884A_THINKPAD,
-       AD1984A_TOUCHSMART,
-       AD1984A_PRECISION,
-       AD1884A_MODELS
-};
-
-static const char * const ad1884a_models[AD1884A_MODELS] = {
-       [AD1884A_AUTO]          = "auto",
-       [AD1884A_DESKTOP]       = "desktop",
-       [AD1884A_LAPTOP]        = "laptop",
-       [AD1884A_MOBILE]        = "mobile",
-       [AD1884A_THINKPAD]      = "thinkpad",
-       [AD1984A_TOUCHSMART]    = "touchsmart",
-       [AD1984A_PRECISION]     = "precision",
-};
-
-static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
-       SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
-       SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
-       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
-       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
-       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
-       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
-       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
-       SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
-       SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
-       {}
-};
-
-static int patch_ad1884a(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
-                                                 ad1884a_models,
-                                                 ad1884a_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1884A_AUTO;
-       }
-
-       if (board_config == AD1884A_AUTO)
-               return ad1884_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 2;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
-       spec->multiout.dac_nids = ad1884a_dac_nids;
-       spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
-       spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
-       spec->adc_nids = ad1884a_adc_nids;
-       spec->capsrc_nids = ad1884a_capsrc_nids;
-       spec->input_mux = &ad1884a_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1884a_base_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1884a_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1884a_loopbacks;
-#endif
-       codec->patch_ops = ad198x_patch_ops;
-
-       /* override some parameters */
-       switch (board_config) {
-       case AD1884A_LAPTOP:
-               spec->mixers[0] = ad1884a_laptop_mixers;
-               spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
-               spec->multiout.dig_out_nid = 0;
-               codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
-               codec->patch_ops.init = ad1884a_laptop_init;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       case AD1884A_MOBILE:
-               spec->mixers[0] = ad1884a_mobile_mixers;
-               spec->init_verbs[0] = ad1884a_mobile_verbs;
-               spec->multiout.dig_out_nid = 0;
-               codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
-               codec->patch_ops.init = ad1884a_hp_init;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       case AD1884A_THINKPAD:
-               spec->mixers[0] = ad1984a_thinkpad_mixers;
-               spec->init_verbs[spec->num_init_verbs++] =
-                       ad1984a_thinkpad_verbs;
-               spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1984a_thinkpad_capture_source;
-               codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
-               codec->patch_ops.init = ad1984a_thinkpad_init;
-               break;
-       case AD1984A_PRECISION:
-               spec->mixers[0] = ad1984a_precision_mixers;
-               spec->init_verbs[spec->num_init_verbs++] =
-                       ad1984a_precision_verbs;
-               spec->multiout.dig_out_nid = 0;
-               codec->patch_ops.unsol_event = ad1984a_precision_unsol_event;
-               codec->patch_ops.init = ad1984a_precision_init;
-               break;
-       case AD1984A_TOUCHSMART:
-               spec->mixers[0] = ad1984a_touchsmart_mixers;
-               spec->init_verbs[0] = ad1984a_touchsmart_verbs;
-               spec->multiout.dig_out_nid = 0;
-               codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
-               codec->patch_ops.init = ad1984a_touchsmart_init;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       }
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1884a  ad1884_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /*
  * AD1882 / AD1882A
  *
@@ -4850,299 +1058,7 @@ static int patch_ad1884a(struct hda_codec *codec)
  * port-G - rear clfe-out (6stack)
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const hda_nid_t ad1882_dac_nids[3] = {
-       0x04, 0x03, 0x05
-};
-
-static const hda_nid_t ad1882_adc_nids[2] = {
-       0x08, 0x09,
-};
-
-static const hda_nid_t ad1882_capsrc_nids[2] = {
-       0x0c, 0x0d,
-};
-
-#define AD1882_SPDIF_OUT       0x02
-
-/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
-static const struct hda_input_mux ad1882_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Front Mic", 0x1 },
-               { "Mic", 0x4 },
-               { "Line", 0x2 },
-               { "CD", 0x3 },
-               { "Mix", 0x7 },
-       },
-};
-
-/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
-static const struct hda_input_mux ad1882a_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Front Mic", 0x1 },
-               { "Mic", 0x4},
-               { "Line", 0x2 },
-               { "Digital Mic", 0x06 },
-               { "Mix", 0x7 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1882_base_mixers[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* SPDIF controls */
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               /* identical with ad1983 */
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = ad198x_ch_mode_info,
-               .get = ad198x_ch_mode_get,
-               .put = ad198x_ch_mode_put,
-       },
-       { } /* end */
-};
-
-/* simple auto-mute control for AD1882 3-stack board */
-#define AD1882_HP_EVENT        0x01
-
-static void ad1882_3stack_automute(struct hda_codec *codec)
-{
-       bool mute = snd_hda_jack_detect(codec, 0x11);
-       snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           mute ? 0 : PIN_OUT);
-}
-
-static int ad1882_3stack_automute_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1882_3stack_automute(codec);
-       return 0;
-}
-
-static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1882_HP_EVENT:
-               ad1882_3stack_automute(codec);
-               break;
-       }
-}
-
-static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct hda_verb ad1882_ch2_init[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       { } /* end */
-};
-
-static const struct hda_verb ad1882_ch4_init[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       { } /* end */
-};
-
-static const struct hda_verb ad1882_ch6_init[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       { } /* end */
-};
-
-static const struct hda_channel_mode ad1882_modes[3] = {
-       { 2, ad1882_ch2_init },
-       { 4, ad1882_ch4_init },
-       { 6, ad1882_ch6_init },
-};
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1882_init_verbs[] = {
-       /* DACs; mute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-A (HP) mixer */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* HP selector - select DAC2 */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Port-D (Line-out) mixer */
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-D pin */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mono-out mixer */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Mono-out pin */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Port-B (front mic) pin */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
-       /* Port-C (line-in) pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
-       /* Port-C mixer - mute as input */
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Port-E (mic-in) pin */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
-       /* Port-E mixer - mute as input */
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Port-F (surround) */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Port-G (CLFE) */
-       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Analog mixer; mute as default */
-       /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-       /* SPDIF output selector */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       { } /* end */
-};
-
-static const struct hda_verb ad1882_3stack_automute_verbs[] = {
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT},
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1882_loopbacks[] = {
-       { 0x20, HDA_INPUT, 0 }, /* Front Mic */
-       { 0x20, HDA_INPUT, 1 }, /* Mic */
-       { 0x20, HDA_INPUT, 4 }, /* Line */
-       { 0x20, HDA_INPUT, 6 }, /* CD */
-       { } /* end */
-};
-#endif
-
-/* models */
-enum {
-       AD1882_AUTO,
-       AD1882_3STACK,
-       AD1882_6STACK,
-       AD1882_3STACK_AUTOMUTE,
-       AD1882_MODELS
-};
-
-static const char * const ad1882_models[AD1986A_MODELS] = {
-       [AD1882_AUTO]           = "auto",
-       [AD1882_3STACK]         = "3stack",
-       [AD1882_6STACK]         = "6stack",
-       [AD1882_3STACK_AUTOMUTE] = "3stack-automute",
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-static int ad1882_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1882(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -5169,110 +1085,20 @@ static int ad1882_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1882(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
-                                                 ad1882_models, NULL);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1882_AUTO;
-       }
-
-       if (board_config == AD1882_AUTO)
-               return ad1882_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 6;
-       spec->multiout.num_dacs = 3;
-       spec->multiout.dac_nids = ad1882_dac_nids;
-       spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
-       spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
-       spec->adc_nids = ad1882_adc_nids;
-       spec->capsrc_nids = ad1882_capsrc_nids;
-       if (codec->vendor_id == 0x11d41882)
-               spec->input_mux = &ad1882_capture_source;
-       else
-               spec->input_mux = &ad1882a_capture_source;
-       spec->num_mixers = 2;
-       spec->mixers[0] = ad1882_base_mixers;
-       if (codec->vendor_id == 0x11d41882)
-               spec->mixers[1] = ad1882_loopback_mixers;
-       else
-               spec->mixers[1] = ad1882a_loopback_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1882_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1882_loopbacks;
-#endif
-       spec->vmaster_nid = 0x04;
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       /* override some parameters */
-       switch (board_config) {
-       default:
-       case AD1882_3STACK:
-       case AD1882_3STACK_AUTOMUTE:
-               spec->num_mixers = 3;
-               spec->mixers[2] = ad1882_3stack_mixers;
-               spec->channel_mode = ad1882_modes;
-               spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
-               spec->need_dac_fix = 1;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               if (board_config != AD1882_3STACK) {
-                       spec->init_verbs[spec->num_init_verbs++] =
-                               ad1882_3stack_automute_verbs;
-                       codec->patch_ops.unsol_event = ad1882_3stack_unsol_event;
-                       codec->patch_ops.init = ad1882_3stack_automute_init;
-               }
-               break;
-       case AD1882_6STACK:
-               spec->num_mixers = 3;
-               spec->mixers[2] = ad1882_6stack_mixers;
-               break;
-       }
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1882   ad1882_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * patch entries
  */
 static const struct hda_codec_preset snd_hda_preset_analog[] = {
-       { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
+       { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 },
        { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
-       { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
+       { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 },
        { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
-       { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
-       { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
+       { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 },
+       { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 },
        { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
        { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
-       { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
+       { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 },
        { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
        { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
        { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
index bd50193..a3a71ac 100644 (file)
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  */
+
+/* *************    Register Documentation   *******************************************************
+ *
+ * Work in progress! Documentation is based on the code in this file.
+ *
+ * --------- HDSPM_controlRegister ---------
+ * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
+ * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
+ * :    .    :    .    :    .    :  x .    :  HDSPM_AudioInterruptEnable \_ setting both bits
+ * :    .    :    .    :    .    :    .   x:  HDSPM_Start                /  enables audio IO
+ * :    .    :    .    :    .    :   x.    :  HDSPM_ClockModeMaster - 1: Master, 0: Slave
+ * :    .    :    .    :    .    :    .210 :  HDSPM_LatencyMask - 3 Bit value for latency
+ * :    .    :    .    :    .    :    .    :      0:64, 1:128, 2:256, 3:512,
+ * :    .    :    .    :    .    :    .    :      4:1024, 5:2048, 6:4096, 7:8192
+ * :x   .    :    .    :    .   x:xx  .    :  HDSPM_FrequencyMask
+ * :    .    :    .    :    .    :10  .    :  HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=??
+ * :    .    :    .    :    .   x:    .    :  <MADI> HDSPM_DoubleSpeed
+ * :x   .    :    .    :    .    :    .    :  <MADI> HDSPM_QuadSpeed
+ * :    .  3 :    .  10:  2 .    :    .    :  HDSPM_SyncRefMask :
+ * :    .    :    .   x:    .    :    .    :  HDSPM_SyncRef0
+ * :    .    :    .  x :    .    :    .    :  HDSPM_SyncRef1
+ * :    .    :    .    :  x .    :    .    :  <AES32> HDSPM_SyncRef2
+ * :    .  x :    .    :    .    :    .    :  <AES32> HDSPM_SyncRef3
+ * :    .    :    .  10:    .    :    .    :  <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn
+ * :    .  3 :    .  10:  2 .    :    .    :  <AES32>  0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn?
+ * :    .  x :    .    :    .    :    .    :  <MADIe> HDSPe_FLOAT_FORMAT
+ * :    .    :    .    : x  .    :    .    :  <MADI> HDSPM_InputSelect0 : 0=optical,1=coax
+ * :    .    :    .    :x   .    :    .    :  <MADI> HDSPM_InputSelect1
+ * :    .    :    .x   :    .    :    .    :  <MADI> HDSPM_clr_tms
+ * :    .    :    .    :    . x  :    .    :  <MADI> HDSPM_TX_64ch
+ * :    .    :    .    :    . x  :    .    :  <AES32> HDSPM_Emphasis
+ * :    .    :    .    :    .x   :    .    :  <MADI> HDSPM_AutoInp
+ * :    .    :    . x  :    .    :    .    :  <MADI> HDSPM_SMUX
+ * :    .    :    .x   :    .    :    .    :  <MADI> HDSPM_clr_tms
+ * :    .    :   x.    :    .    :    .    :  <MADI> HDSPM_taxi_reset
+ * :    .   x:    .    :    .    :    .    :  <MADI> HDSPM_LineOut
+ * :    .   x:    .    :    .    :    .    :  <AES32> ??????????????????
+ * :    .    :   x.    :    .    :    .    :  <AES32> HDSPM_WCK48
+ * :    .    :    .    :    .x   :    .    :  <AES32> HDSPM_Dolby
+ * :    .    : x  .    :    .    :    .    :  HDSPM_Midi0InterruptEnable
+ * :    .    :x   .    :    .    :    .    :  HDSPM_Midi1InterruptEnable
+ * :    .    :  x .    :    .    :    .    :  HDSPM_Midi2InterruptEnable
+ * :    . x  :    .    :    .    :    .    :  <MADI> HDSPM_Midi3InterruptEnable
+ * :    . x  :    .    :    .    :    .    :  <AES32> HDSPM_DS_DoubleWire
+ * :    .x   :    .    :    .    :    .    :  <AES32> HDSPM_QS_DoubleWire
+ * :   x.    :    .    :    .    :    .    :  <AES32> HDSPM_QS_QuadWire
+ * :    .    :    .    :    .  x :    .    :  <AES32> HDSPM_Professional
+ * : x  .    :    .    :    .    :    .    :  HDSPM_wclk_sel
+ * :    .    :    .    :    .    :    .    :
+ * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
+ * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit
+ *
+ *
+ *
+ * AIO / RayDAT only
+ *
+ * ------------ HDSPM_WR_SETTINGS ----------
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
+ * :1098.7654:3210.9876:5432.1098:7654.3210:
+ * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
+ * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
+ * :    .    :    .    :    .    :    .   x: HDSPM_c0Master 1: Master, 0: Slave
+ * :    .    :    .    :    .    :    .  x : HDSPM_c0_SyncRef0
+ * :    .    :    .    :    .    :    . x  : HDSPM_c0_SyncRef1
+ * :    .    :    .    :    .    :    .x   : HDSPM_c0_SyncRef2
+ * :    .    :    .    :    .    :   x.    : HDSPM_c0_SyncRef3
+ * :    .    :    .    :    .    :   3.210 : HDSPM_c0_SyncRefMask:
+ * :    .    :    .    :    .    :    .    :  RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4,
+ * :    .    :    .    :    .    :    .    :          9:TCO, 10:SyncIn
+ * :    .    :    .    :    .    :    .    :  AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT,
+ * :    .    :    .    :    .    :    .    :          9:TCO, 10:SyncIn
+ * :    .    :    .    :    .    :    .    :
+ * :    .    :    .    :    .    :    .    :
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
+ * :1098.7654:3210.9876:5432.1098:7654.3210:
+ * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
+ * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
+ *
+ */
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -95,7 +186,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 #define HDSPM_controlRegister       64
 #define HDSPM_interruptConfirmation  96
 #define HDSPM_control2Reg           256  /* not in specs ???????? */
-#define HDSPM_freqReg                256  /* for AES32 */
+#define HDSPM_freqReg                256  /* for setting arbitrary clock values (DDS feature) */
 #define HDSPM_midiDataOut0          352  /* just believe in old code */
 #define HDSPM_midiDataOut1          356
 #define HDSPM_eeprom_wr                     384  /* for AES32 */
@@ -258,6 +349,25 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 
 #define HDSPM_wclk_sel (1<<30)
 
+/* additional control register bits for AIO*/
+#define HDSPM_c0_Wck48                         0x20 /* also RayDAT */
+#define HDSPM_c0_Input0                                0x1000
+#define HDSPM_c0_Input1                                0x2000
+#define HDSPM_c0_Spdif_Opt                     0x4000
+#define HDSPM_c0_Pro                           0x8000
+#define HDSPM_c0_clr_tms                       0x10000
+#define HDSPM_c0_AEB1                          0x20000
+#define HDSPM_c0_AEB2                          0x40000
+#define HDSPM_c0_LineOut                       0x80000
+#define HDSPM_c0_AD_GAIN0                      0x100000
+#define HDSPM_c0_AD_GAIN1                      0x200000
+#define HDSPM_c0_DA_GAIN0                      0x400000
+#define HDSPM_c0_DA_GAIN1                      0x800000
+#define HDSPM_c0_PH_GAIN0                      0x1000000
+#define HDSPM_c0_PH_GAIN1                      0x2000000
+#define HDSPM_c0_Sym6db                                0x4000000
+
+
 /* --- bit helper defines */
 #define HDSPM_LatencyMask    (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
 #define HDSPM_FrequencyMask  (HDSPM_Frequency0|HDSPM_Frequency1|\
@@ -341,11 +451,11 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 #define HDSPM_madiLock           (1<<3)        /* MADI Locked =1, no=0 */
 #define HDSPM_madiSync          (1<<18) /* MADI is in sync */
 
-#define HDSPM_tcoLock    0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */
-#define HDSPM_tcoSync    0x10000000 /* Optional TCO sync status */
+#define HDSPM_tcoLockMadi    0x00000020 /* Optional TCO locked status for HDSPe MADI*/
+#define HDSPM_tcoSync    0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/
 
-#define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */
-#define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */
+#define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */
+#define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */
 
 #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
                        /* since 64byte accurate, last 6 bits are not used */
@@ -363,7 +473,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
                                         * Interrupt
                                         */
 #define HDSPM_tco_detect         0x08000000
-#define HDSPM_tco_lock          0x20000000
+#define HDSPM_tcoLockAes         0x20000000 /* Optional TCO locked status for HDSPe AES */
 
 #define HDSPM_s2_tco_detect      0x00000040
 #define HDSPM_s2_AEBO_D          0x00000080
@@ -461,7 +571,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
 #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
 #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
-#define HDSPM_AES32_AUTOSYNC_FROM_NONE 9
+#define HDSPM_AES32_AUTOSYNC_FROM_TCO 9
+#define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10
+#define HDSPM_AES32_AUTOSYNC_FROM_NONE 11
 
 /*  status2 */
 /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
@@ -537,36 +649,39 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 /* names for speed modes */
 static char *hdspm_speed_names[] = { "single", "double", "quad" };
 
-static char *texts_autosync_aes_tco[] = { "Word Clock",
+static const char *const texts_autosync_aes_tco[] = { "Word Clock",
                                          "AES1", "AES2", "AES3", "AES4",
                                          "AES5", "AES6", "AES7", "AES8",
-                                         "TCO" };
-static char *texts_autosync_aes[] = { "Word Clock",
+                                         "TCO", "Sync In"
+};
+static const char *const texts_autosync_aes[] = { "Word Clock",
                                      "AES1", "AES2", "AES3", "AES4",
-                                     "AES5", "AES6", "AES7", "AES8" };
-static char *texts_autosync_madi_tco[] = { "Word Clock",
+                                     "AES5", "AES6", "AES7", "AES8",
+                                     "Sync In"
+};
+static const char *const texts_autosync_madi_tco[] = { "Word Clock",
                                           "MADI", "TCO", "Sync In" };
-static char *texts_autosync_madi[] = { "Word Clock",
+static const char *const texts_autosync_madi[] = { "Word Clock",
                                       "MADI", "Sync In" };
 
-static char *texts_autosync_raydat_tco[] = {
+static const char *const texts_autosync_raydat_tco[] = {
        "Word Clock",
        "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
        "AES", "SPDIF", "TCO", "Sync In"
 };
-static char *texts_autosync_raydat[] = {
+static const char *const texts_autosync_raydat[] = {
        "Word Clock",
        "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
        "AES", "SPDIF", "Sync In"
 };
-static char *texts_autosync_aio_tco[] = {
+static const char *const texts_autosync_aio_tco[] = {
        "Word Clock",
        "ADAT", "AES", "SPDIF", "TCO", "Sync In"
 };
-static char *texts_autosync_aio[] = { "Word Clock",
+static const char *const texts_autosync_aio[] = { "Word Clock",
                                      "ADAT", "AES", "SPDIF", "Sync In" };
 
-static char *texts_freq[] = {
+static const char *const texts_freq[] = {
        "No Lock",
        "32 kHz",
        "44.1 kHz",
@@ -629,7 +744,8 @@ static char *texts_ports_aio_in_ss[] = {
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
        "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
-       "ADAT.7", "ADAT.8"
+       "ADAT.7", "ADAT.8",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_out_ss[] = {
@@ -638,14 +754,16 @@ static char *texts_ports_aio_out_ss[] = {
        "SPDIF.L", "SPDIF.R",
        "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
        "ADAT.7", "ADAT.8",
-       "Phone.L", "Phone.R"
+       "Phone.L", "Phone.R",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_in_ds[] = {
        "Analogue.L", "Analogue.R",
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
-       "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4"
+       "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_out_ds[] = {
@@ -653,14 +771,16 @@ static char *texts_ports_aio_out_ds[] = {
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
        "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
-       "Phone.L", "Phone.R"
+       "Phone.L", "Phone.R",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_in_qs[] = {
        "Analogue.L", "Analogue.R",
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
-       "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4"
+       "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_out_qs[] = {
@@ -668,7 +788,8 @@ static char *texts_ports_aio_out_qs[] = {
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
        "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
-       "Phone.L", "Phone.R"
+       "Phone.L", "Phone.R",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aes32[] = {
@@ -745,8 +866,8 @@ static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = {
        8, 9,                   /* aes in, */
        10, 11,                 /* spdif in */
        12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */
-       -1, -1,
-       -1, -1, -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -760,7 +881,8 @@ static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = {
        10, 11,                 /* spdif out */
        12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */
        6, 7,                   /* phone out */
-       -1, -1, -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -773,7 +895,8 @@ static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = {
        8, 9,                   /* aes in */
        10, 11,                 /* spdif in */
        12, 14, 16, 18,         /* adat in */
-       -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -788,7 +911,7 @@ static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = {
        10, 11,                 /* spdif out */
        12, 14, 16, 18,         /* adat out */
        6, 7,                   /* phone out */
-       -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -802,7 +925,8 @@ static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = {
        8, 9,                   /* aes in */
        10, 11,                 /* spdif in */
        12, 16,                 /* adat in */
-       -1, -1, -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -817,7 +941,8 @@ static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = {
        10, 11,                 /* spdif out */
        12, 16,                 /* adat out */
        6, 7,                   /* phone out */
-       -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -856,11 +981,11 @@ struct hdspm_midi {
 };
 
 struct hdspm_tco {
-       int input;
-       int framerate;
-       int wordclock;
-       int samplerate;
-       int pull;
+       int input; /* 0: LTC, 1:Video, 2: WC*/
+       int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */
+       int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */
+       int samplerate; /* 0=44.1, 1=48, 2= freq from app */
+       int pull; /*   0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/
        int term; /* 0 = off, 1 = on */
 };
 
@@ -879,7 +1004,7 @@ struct hdspm {
 
        u32 control_register;   /* cached value */
        u32 control2_register;  /* cached value */
-       u32 settings_register;
+       u32 settings_register;  /* cached value for AIO / RayDat (sync reference, master/slave) */
 
        struct hdspm_midi midi[4];
        struct tasklet_struct midi_tasklet;
@@ -941,7 +1066,7 @@ struct hdspm {
 
        struct hdspm_tco *tco;  /* NULL if no TCO detected */
 
-       char **texts_autosync;
+       const char *const *texts_autosync;
        int texts_autosync_items;
 
        cycles_t last_interrupt;
@@ -976,12 +1101,24 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm);
 static inline int hdspm_get_pll_freq(struct hdspm *hdspm);
 static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm);
 static int hdspm_autosync_ref(struct hdspm *hdspm);
+static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out);
 static int snd_hdspm_set_defaults(struct hdspm *hdspm);
 static int hdspm_system_clock_mode(struct hdspm *hdspm);
 static void hdspm_set_sgbuf(struct hdspm *hdspm,
                            struct snd_pcm_substream *substream,
                             unsigned int reg, int channels);
 
+static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx);
+static int hdspm_wc_sync_check(struct hdspm *hdspm);
+static int hdspm_tco_sync_check(struct hdspm *hdspm);
+static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
+
+static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index);
+static int hdspm_get_tco_sample_rate(struct hdspm *hdspm);
+static int hdspm_get_wc_sample_rate(struct hdspm *hdspm);
+
+
+
 static inline int HDSPM_bit2freq(int n)
 {
        static const int bit2freq_tab[] = {
@@ -992,6 +1129,12 @@ static inline int HDSPM_bit2freq(int n)
        return bit2freq_tab[n];
 }
 
+static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm)
+{
+       return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type));
+}
+
+
 /* Write/read to/from HDSPM with Adresses in Bytes
    not words but only 32Bit writes are allowed */
 
@@ -1111,10 +1254,7 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
        return rate;
 }
 
-static int hdspm_tco_sync_check(struct hdspm *hdspm);
-static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
-
-/* check for external sample rate */
+/* check for external sample rate, returns the sample rate in Hz*/
 static int hdspm_external_sample_rate(struct hdspm *hdspm)
 {
        unsigned int status, status2, timecode;
@@ -1127,17 +1267,36 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
 
                syncref = hdspm_autosync_ref(hdspm);
+               switch (syncref) {
+               case HDSPM_AES32_AUTOSYNC_FROM_WORD:
+               /* Check WC sync and get sample rate */
+                       if (hdspm_wc_sync_check(hdspm))
+                               return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm));
+                       break;
 
-               if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD &&
-                               status & HDSPM_AES32_wcLock)
-                       return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF);
+               case HDSPM_AES32_AUTOSYNC_FROM_AES1:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES2:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES3:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES4:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES5:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES6:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES7:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES8:
+               /* Check AES sync and get sample rate */
+                       if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))
+                               return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm,
+                                                       syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1));
+                       break;
 
-               if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 &&
-                               syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 &&
-                               status2 & (HDSPM_LockAES >>
-                               (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)))
-                       return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF);
-               return 0;
+
+               case HDSPM_AES32_AUTOSYNC_FROM_TCO:
+               /* Check TCO sync and get sample rate */
+                       if (hdspm_tco_sync_check(hdspm))
+                               return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm));
+                       break;
+               default:
+                       return 0;
+               } /* end switch(syncref) */
                break;
 
        case MADIface:
@@ -2129,6 +2288,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
                status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
                return (status >> 16) & 0xF;
                break;
+       case AES32:
+               status = hdspm_read(hdspm, HDSPM_statusRegister);
+               return (status >> HDSPM_AES32_wcFreq_bit) & 0xF;
        default:
                break;
        }
@@ -2152,6 +2314,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
                        status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
                        return (status >> 20) & 0xF;
                        break;
+               case AES32:
+                       status = hdspm_read(hdspm, HDSPM_statusRegister);
+                       return (status >> 1) & 0xF;
                default:
                        break;
                }
@@ -2183,6 +2348,23 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
        return 0;
 }
 
+/**
+ * Returns the AES sample rate class for the given card.
+ **/
+static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index)
+{
+       int timecode;
+
+       switch (hdspm->io_type) {
+       case AES32:
+               timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
+               return (timecode >> (4*index)) & 0xF;
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
 
 /**
  * Returns the sample rate class for input source <idx> for
@@ -2196,16 +2378,24 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
 }
 
 #define ENUMERATED_CTL_INFO(info, texts) \
-{ \
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \
-       uinfo->count = 1; \
-       uinfo->value.enumerated.items = ARRAY_SIZE(texts); \
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \
-               uinfo->value.enumerated.item =  uinfo->value.enumerated.items - 1; \
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \
-}
+       snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts)
 
 
+/* Helper function to query the external sample rate and return the
+ * corresponding enum to be returned to userspace.
+ */
+static int hdspm_external_rate_to_enum(struct hdspm *hdspm)
+{
+       int rate = hdspm_external_sample_rate(hdspm);
+       int i, selected_rate = 0;
+       for (i = 1; i < 10; i++)
+               if (HDSPM_bit2freq(i) == rate) {
+                       selected_rate = i;
+                       break;
+               }
+       return selected_rate;
+}
+
 
 #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -2270,7 +2460,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
                default:
                        ucontrol->value.enumerated.item[0] =
                                hdspm_get_s1_sample_rate(hdspm,
-                                               ucontrol->id.index-1);
+                                               kcontrol->private_value-1);
                }
                break;
 
@@ -2289,28 +2479,24 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
                        ucontrol->value.enumerated.item[0] =
                                hdspm_get_sync_in_sample_rate(hdspm);
                        break;
+               case 11: /* External Rate */
+                       ucontrol->value.enumerated.item[0] =
+                               hdspm_external_rate_to_enum(hdspm);
+                       break;
                default: /* AES1 to AES8 */
                        ucontrol->value.enumerated.item[0] =
-                               hdspm_get_s1_sample_rate(hdspm,
-                                               kcontrol->private_value-1);
+                               hdspm_get_aes_sample_rate(hdspm,
+                                               kcontrol->private_value -
+                                               HDSPM_AES32_AUTOSYNC_FROM_AES1);
                        break;
                }
                break;
 
        case MADI:
        case MADIface:
-               {
-                       int rate = hdspm_external_sample_rate(hdspm);
-                       int i, selected_rate = 0;
-                       for (i = 1; i < 10; i++)
-                               if (HDSPM_bit2freq(i) == rate) {
-                                       selected_rate = i;
-                                       break;
-                               }
-                       ucontrol->value.enumerated.item[0] = selected_rate;
-               }
+               ucontrol->value.enumerated.item[0] =
+                       hdspm_external_rate_to_enum(hdspm);
                break;
-
        default:
                break;
        }
@@ -2359,33 +2545,17 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm)
  **/
 static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode)
 {
-       switch (hdspm->io_type) {
-       case AIO:
-       case RayDAT:
-               if (0 == mode)
-                       hdspm->settings_register |= HDSPM_c0Master;
-               else
-                       hdspm->settings_register &= ~HDSPM_c0Master;
-
-               hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
-               break;
-
-       default:
-               if (0 == mode)
-                       hdspm->control_register |= HDSPM_ClockModeMaster;
-               else
-                       hdspm->control_register &= ~HDSPM_ClockModeMaster;
-
-               hdspm_write(hdspm, HDSPM_controlRegister,
-                               hdspm->control_register);
-       }
+       hdspm_set_toggle_setting(hdspm,
+                       (hdspm_is_raydat_or_aio(hdspm)) ?
+                       HDSPM_c0Master : HDSPM_ClockModeMaster,
+                       (0 == mode));
 }
 
 
 static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol,
                                            struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "Master", "AutoSync" };
+       static const char *const texts[] = { "Master", "AutoSync" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -2809,16 +2979,7 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
 {
        struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = hdspm->texts_autosync_items;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                       uinfo->value.enumerated.items - 1;
-
-       strcpy(uinfo->value.enumerated.name,
-                       hdspm->texts_autosync[uinfo->value.enumerated.item]);
+       snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync);
 
        return 0;
 }
@@ -2873,19 +3034,20 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
 
 static int hdspm_autosync_ref(struct hdspm *hdspm)
 {
+       /* This looks at the autosync selected sync reference */
        if (AES32 == hdspm->io_type) {
+
                unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
-               unsigned int syncref =
-                       (status >> HDSPM_AES32_syncref_bit) & 0xF;
-               if (syncref == 0)
-                       return HDSPM_AES32_AUTOSYNC_FROM_WORD;
-               if (syncref <= 8)
+               unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF;
+               if ((syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD) &&
+                               (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN)) {
                        return syncref;
+               }
                return HDSPM_AES32_AUTOSYNC_FROM_NONE;
+
        } else if (MADI == hdspm->io_type) {
-               /* This looks at the autosync selected sync reference */
-               unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
 
+               unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
                switch (status2 & HDSPM_SelSyncRefMask) {
                case HDSPM_SelSyncRef_WORD:
                        return HDSPM_AUTOSYNC_FROM_WORD;
@@ -2898,7 +3060,7 @@ static int hdspm_autosync_ref(struct hdspm *hdspm)
                case HDSPM_SelSyncRef_NVALID:
                        return HDSPM_AUTOSYNC_FROM_NONE;
                default:
-                       return 0;
+                       return HDSPM_AUTOSYNC_FROM_NONE;
                }
 
        }
@@ -2912,31 +3074,15 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
        struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
        if (AES32 == hdspm->io_type) {
-               static char *texts[] = { "WordClock", "AES1", "AES2", "AES3",
-                       "AES4", "AES5", "AES6", "AES7", "AES8", "None"};
-
-               uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-               uinfo->count = 1;
-               uinfo->value.enumerated.items = 10;
-               if (uinfo->value.enumerated.item >=
-                   uinfo->value.enumerated.items)
-                       uinfo->value.enumerated.item =
-                               uinfo->value.enumerated.items - 1;
-               strcpy(uinfo->value.enumerated.name,
-                               texts[uinfo->value.enumerated.item]);
+               static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3",
+                       "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"};
+
+               ENUMERATED_CTL_INFO(uinfo, texts);
        } else if (MADI == hdspm->io_type) {
-               static char *texts[] = {"Word Clock", "MADI", "TCO",
+               static const char *const texts[] = {"Word Clock", "MADI", "TCO",
                        "Sync In", "None" };
 
-               uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-               uinfo->count = 1;
-               uinfo->value.enumerated.items = 5;
-               if (uinfo->value.enumerated.item >=
-                               uinfo->value.enumerated.items)
-                       uinfo->value.enumerated.item =
-                               uinfo->value.enumerated.items - 1;
-               strcpy(uinfo->value.enumerated.name,
-                               texts[uinfo->value.enumerated.item]);
+               ENUMERATED_CTL_INFO(uinfo, texts);
        }
        return 0;
 }
@@ -2964,7 +3110,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = {"No video", "NTSC", "PAL"};
+       static const char *const texts[] = {"No video", "NTSC", "PAL"};
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3010,7 +3156,7 @@ static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
+       static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
                                "30 fps"};
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
@@ -3067,16 +3213,35 @@ static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol,
 
 static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask)
 {
-       return (hdspm->control_register & regmask) ? 1 : 0;
+       u32 reg;
+
+       if (hdspm_is_raydat_or_aio(hdspm))
+               reg = hdspm->settings_register;
+       else
+               reg = hdspm->control_register;
+
+       return (reg & regmask) ? 1 : 0;
 }
 
 static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out)
 {
+       u32 *reg;
+       u32 target_reg;
+
+       if (hdspm_is_raydat_or_aio(hdspm)) {
+               reg = &(hdspm->settings_register);
+               target_reg = HDSPM_WR_SETTINGS;
+       } else {
+               reg = &(hdspm->control_register);
+               target_reg = HDSPM_controlRegister;
+       }
+
        if (out)
-               hdspm->control_register |= regmask;
+               *reg |= regmask;
        else
-               hdspm->control_register &= ~regmask;
-       hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+               *reg &= ~regmask;
+
+       hdspm_write(hdspm, target_reg, *reg);
 
        return 0;
 }
@@ -3141,7 +3306,7 @@ static int hdspm_set_input_select(struct hdspm * hdspm, int out)
 static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "optical", "coaxial" };
+       static const char *const texts[] = { "optical", "coaxial" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3203,7 +3368,7 @@ static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds)
 static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "Single", "Double" };
+       static const char *const texts[] = { "Single", "Double" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3276,7 +3441,7 @@ static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode)
 static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "Single", "Double", "Quad" };
+       static const char *const texts[] = { "Single", "Double", "Quad" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3313,6 +3478,84 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+#define HDSPM_CONTROL_TRISTATE(xname, xindex) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .private_value = xindex, \
+       .info = snd_hdspm_info_tristate, \
+       .get = snd_hdspm_get_tristate, \
+       .put = snd_hdspm_put_tristate \
+}
+
+static int hdspm_tristate(struct hdspm *hdspm, u32 regmask)
+{
+       u32 reg = hdspm->settings_register & (regmask * 3);
+       return reg / regmask;
+}
+
+static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask)
+{
+       hdspm->settings_register &= ~(regmask * 3);
+       hdspm->settings_register |= (regmask * mode);
+       hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
+
+       return 0;
+}
+
+static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       u32 regmask = kcontrol->private_value;
+
+       static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" };
+       static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" };
+
+       switch (regmask) {
+       case HDSPM_c0_Input0:
+               ENUMERATED_CTL_INFO(uinfo, texts_spdif);
+               break;
+       default:
+               ENUMERATED_CTL_INFO(uinfo, texts_levels);
+               break;
+       }
+       return 0;
+}
+
+static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+       u32 regmask = kcontrol->private_value;
+
+       spin_lock_irq(&hdspm->lock);
+       ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask);
+       spin_unlock_irq(&hdspm->lock);
+       return 0;
+}
+
+static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+       u32 regmask = kcontrol->private_value;
+       int change;
+       int val;
+
+       if (!snd_hdspm_use_is_exclusive(hdspm))
+               return -EBUSY;
+       val = ucontrol->value.integer.value[0];
+       if (val < 0)
+               val = 0;
+       if (val > 2)
+               val = 2;
+
+       spin_lock_irq(&hdspm->lock);
+       change = val != hdspm_tristate(hdspm, regmask);
+       hdspm_set_tristate(hdspm, val, regmask);
+       spin_unlock_irq(&hdspm->lock);
+       return change;
+}
+
 #define HDSPM_MADI_SPEEDMODE(xname, xindex) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
        .name = xname, \
@@ -3352,7 +3595,7 @@ static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode)
 static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "Single", "Double", "Quad" };
+       static const char *const texts[] = { "Single", "Double", "Quad" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3587,7 +3830,7 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" };
+       static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3595,7 +3838,7 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "No Lock", "Lock" };
+       static const char *const texts[] = { "No Lock", "Lock" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3745,9 +3988,18 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm)
        if (hdspm->tco) {
                switch (hdspm->io_type) {
                case MADI:
+                       status = hdspm_read(hdspm, HDSPM_statusRegister);
+                       if (status & HDSPM_tcoLockMadi) {
+                               if (status & HDSPM_tcoSync)
+                                       return 2;
+                               else
+                                       return 1;
+                       }
+                       return 0;
+                       break;
                case AES32:
                        status = hdspm_read(hdspm, HDSPM_statusRegister);
-                       if (status & HDSPM_tcoLock) {
+                       if (status & HDSPM_tcoLockAes) {
                                if (status & HDSPM_tcoSync)
                                        return 2;
                                else
@@ -3807,7 +4059,8 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
                case 5: /* SYNC IN */
                        val = hdspm_sync_in_sync_check(hdspm); break;
                default:
-                       val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1);
+                       val = hdspm_s1_sync_check(hdspm,
+                                       kcontrol->private_value-1);
                }
                break;
 
@@ -3975,7 +4228,8 @@ static void hdspm_tco_write(struct hdspm *hdspm)
 static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "44.1 kHz", "48 kHz" };
+       /* TODO freq from app could be supported here, see tco->samplerate */
+       static const char *const texts[] = { "44.1 kHz", "48 kHz" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -4021,7 +4275,8 @@ static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" };
+       static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %",
+               "+ 4 %", "- 4 %" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -4066,7 +4321,7 @@ static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol,
                                             struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
+       static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -4112,7 +4367,7 @@ static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "24 fps", "25 fps", "29.97fps",
+       static const char *const texts[] = { "24 fps", "25 fps", "29.97fps",
                "29.97 dfps", "30 fps", "30 dfps" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
@@ -4159,7 +4414,7 @@ static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "LTC", "Video", "WCK" };
+       static const char *const texts[] = { "LTC", "Video", "WCK" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -4284,7 +4539,6 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
        HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
        HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
        HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
-       HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
        HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
        HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
        HDSPM_SYNC_CHECK("WC SyncCheck", 0),
@@ -4298,7 +4552,16 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
        HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2),
        HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3),
        HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4),
-       HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5)
+       HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5),
+       HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0),
+       HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt),
+       HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
+       HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1),
+       HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db),
+       HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48),
+       HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0),
+       HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0),
+       HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0)
 
                /*
                   HDSPM_INPUT_SELECT("Input Select", 0),
@@ -4335,7 +4598,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = {
        HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5),
        HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6),
        HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7),
-       HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8)
+       HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8),
+       HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
+       HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48)
 };
 
 static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
@@ -4345,7 +4610,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
        HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
        HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
        HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
-       HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
+       HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11),
        HDSPM_SYNC_CHECK("WC Sync Check", 0),
        HDSPM_SYNC_CHECK("AES1 Sync Check", 1),
        HDSPM_SYNC_CHECK("AES2 Sync Check", 2),
@@ -4501,77 +4766,22 @@ static int snd_hdspm_create_controls(struct snd_card *card,
  ------------------------------------------------------------*/
 
 static void
-snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
-                        struct snd_info_buffer *buffer)
+snd_hdspm_proc_read_tco(struct snd_info_entry *entry,
+                                       struct snd_info_buffer *buffer)
 {
        struct hdspm *hdspm = entry->private_data;
-       unsigned int status, status2, control, freq;
-
-       char *pref_sync_ref;
-       char *autosync_ref;
-       char *system_clock_mode;
-       char *insel;
-       int x, x2;
-
-       /* TCO stuff */
+       unsigned int status, control;
        int a, ltc, frames, seconds, minutes, hours;
        unsigned int period;
        u64 freq_const = 0;
        u32 rate;
 
+       snd_iprintf(buffer, "--- TCO ---\n");
+
        status = hdspm_read(hdspm, HDSPM_statusRegister);
-       status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
        control = hdspm->control_register;
-       freq = hdspm_read(hdspm, HDSPM_timecodeRegister);
 
-       snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
-                       hdspm->card_name, hdspm->card->number + 1,
-                       hdspm->firmware_rev,
-                       (status2 & HDSPM_version0) |
-                       (status2 & HDSPM_version1) | (status2 &
-                               HDSPM_version2));
-
-       snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
-                       (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
-                       hdspm->serial);
 
-       snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
-                       hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
-
-       snd_iprintf(buffer, "--- System ---\n");
-
-       snd_iprintf(buffer,
-               "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
-               status & HDSPM_audioIRQPending,
-               (status & HDSPM_midi0IRQPending) ? 1 : 0,
-               (status & HDSPM_midi1IRQPending) ? 1 : 0,
-               hdspm->irq_count);
-       snd_iprintf(buffer,
-               "HW pointer: id = %d, rawptr = %d (%d->%d) "
-               "estimated= %ld (bytes)\n",
-               ((status & HDSPM_BufferID) ? 1 : 0),
-               (status & HDSPM_BufferPositionMask),
-               (status & HDSPM_BufferPositionMask) %
-               (2 * (int)hdspm->period_bytes),
-               ((status & HDSPM_BufferPositionMask) - 64) %
-               (2 * (int)hdspm->period_bytes),
-               (long) hdspm_hw_pointer(hdspm) * 4);
-
-       snd_iprintf(buffer,
-               "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
-               hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
-               hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
-               hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
-               hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
-       snd_iprintf(buffer,
-               "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
-               hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
-               hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
-       snd_iprintf(buffer,
-               "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
-               "status2=0x%x\n",
-               hdspm->control_register, hdspm->control2_register,
-               status, status2);
        if (status & HDSPM_tco_detect) {
                snd_iprintf(buffer, "TCO module detected.\n");
                a = hdspm_read(hdspm, HDSPM_RD_TCO+4);
@@ -4665,6 +4875,75 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
        } else {
                snd_iprintf(buffer, "No TCO module detected.\n");
        }
+}
+
+static void
+snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
+                        struct snd_info_buffer *buffer)
+{
+       struct hdspm *hdspm = entry->private_data;
+       unsigned int status, status2, control, freq;
+
+       char *pref_sync_ref;
+       char *autosync_ref;
+       char *system_clock_mode;
+       char *insel;
+       int x, x2;
+
+       status = hdspm_read(hdspm, HDSPM_statusRegister);
+       status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+       control = hdspm->control_register;
+       freq = hdspm_read(hdspm, HDSPM_timecodeRegister);
+
+       snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
+                       hdspm->card_name, hdspm->card->number + 1,
+                       hdspm->firmware_rev,
+                       (status2 & HDSPM_version0) |
+                       (status2 & HDSPM_version1) | (status2 &
+                               HDSPM_version2));
+
+       snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
+                       (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
+                       hdspm->serial);
+
+       snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
+                       hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
+
+       snd_iprintf(buffer, "--- System ---\n");
+
+       snd_iprintf(buffer,
+               "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
+               status & HDSPM_audioIRQPending,
+               (status & HDSPM_midi0IRQPending) ? 1 : 0,
+               (status & HDSPM_midi1IRQPending) ? 1 : 0,
+               hdspm->irq_count);
+       snd_iprintf(buffer,
+               "HW pointer: id = %d, rawptr = %d (%d->%d) "
+               "estimated= %ld (bytes)\n",
+               ((status & HDSPM_BufferID) ? 1 : 0),
+               (status & HDSPM_BufferPositionMask),
+               (status & HDSPM_BufferPositionMask) %
+               (2 * (int)hdspm->period_bytes),
+               ((status & HDSPM_BufferPositionMask) - 64) %
+               (2 * (int)hdspm->period_bytes),
+               (long) hdspm_hw_pointer(hdspm) * 4);
+
+       snd_iprintf(buffer,
+               "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
+               hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
+               hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
+               hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
+               hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
+       snd_iprintf(buffer,
+               "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
+               hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
+               hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
+       snd_iprintf(buffer,
+               "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
+               "status2=0x%x\n",
+               hdspm->control_register, hdspm->control2_register,
+               status, status2);
+
 
        snd_iprintf(buffer, "--- Settings ---\n");
 
@@ -4768,6 +5047,9 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
                (status & HDSPM_RX_64ch) ? "64 channels" :
                "56 channels");
 
+       /* call readout function for TCO specific status */
+       snd_hdspm_proc_read_tco(entry, buffer);
+
        snd_iprintf(buffer, "\n");
 }
 
@@ -4909,11 +5191,18 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
                autosync_ref = "AES7"; break;
        case HDSPM_AES32_AUTOSYNC_FROM_AES8:
                autosync_ref = "AES8"; break;
+       case HDSPM_AES32_AUTOSYNC_FROM_TCO:
+               autosync_ref = "TCO"; break;
+       case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN:
+               autosync_ref = "Sync In"; break;
        default:
                autosync_ref = "---"; break;
        }
        snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref);
 
+       /* call readout function for TCO specific status */
+       snd_hdspm_proc_read_tco(entry, buffer);
+
        snd_iprintf(buffer, "\n");
 }
 
@@ -5097,7 +5386,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
 
        case AES32:
                hdspm->control_register =
-                       HDSPM_ClockModeMaster | /* Master Cloack Mode on */
+                       HDSPM_ClockModeMaster | /* Master Clock Mode on */
                        hdspm_encode_latency(7) | /* latency max=8192samples */
                        HDSPM_SyncRef0 |        /* AES1 is syncclock */
                        HDSPM_LineOut | /* Analog output in */
@@ -5123,9 +5412,8 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
 
        all_in_all_mixer(hdspm, 0 * UNITY_GAIN);
 
-       if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) {
+       if (hdspm_is_raydat_or_aio(hdspm))
                hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
-       }
 
        /* set a default rate so that the channel map is set up. */
        hdspm_set_rate(hdspm, 48000, 1);
@@ -5371,6 +5659,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
           */
 
 
+       /*  For AES cards, the float format bit is the same as the
+        *  preferred sync reference. Since we don't want to break
+        *  sync settings, we have to skip the remaining part of this
+        *  function.
+        */
+       if (hdspm->io_type == AES32) {
+               return 0;
+       }
+
+
        /* Switch to native float format if requested */
        if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) {
                if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT))
@@ -6479,10 +6777,6 @@ static int snd_hdspm_create(struct snd_card *card,
                break;
 
        case AIO:
-               if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
-                       snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n");
-               }
-
                hdspm->ss_in_channels = AIO_IN_SS_CHANNELS;
                hdspm->ds_in_channels = AIO_IN_DS_CHANNELS;
                hdspm->qs_in_channels = AIO_IN_QS_CHANNELS;
@@ -6490,6 +6784,20 @@ static int snd_hdspm_create(struct snd_card *card,
                hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS;
                hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS;
 
+               if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
+                       snd_printk(KERN_INFO "HDSPM: AEB input board found\n");
+                       hdspm->ss_in_channels += 4;
+                       hdspm->ds_in_channels += 4;
+                       hdspm->qs_in_channels += 4;
+               }
+
+               if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) {
+                       snd_printk(KERN_INFO "HDSPM: AEB output board found\n");
+                       hdspm->ss_out_channels += 4;
+                       hdspm->ds_out_channels += 4;
+                       hdspm->qs_out_channels += 4;
+               }
+
                hdspm->channel_map_out_ss = channel_map_aio_out_ss;
                hdspm->channel_map_out_ds = channel_map_aio_out_ds;
                hdspm->channel_map_out_qs = channel_map_aio_out_qs;
@@ -6558,6 +6866,7 @@ static int snd_hdspm_create(struct snd_card *card,
                break;
 
        case MADI:
+       case AES32:
                if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) {
                        hdspm->midiPorts++;
                        hdspm->tco = kzalloc(sizeof(struct hdspm_tco),
@@ -6565,7 +6874,7 @@ static int snd_hdspm_create(struct snd_card *card,
                        if (NULL != hdspm->tco) {
                                hdspm_tco_write(hdspm);
                        }
-                       snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n");
+                       snd_printk(KERN_INFO "HDSPM: MADI/AES TCO module found\n");
                } else {
                        hdspm->tco = NULL;
                }
@@ -6580,10 +6889,12 @@ static int snd_hdspm_create(struct snd_card *card,
        case AES32:
                if (hdspm->tco) {
                        hdspm->texts_autosync = texts_autosync_aes_tco;
-                       hdspm->texts_autosync_items = 10;
+                       hdspm->texts_autosync_items =
+                               ARRAY_SIZE(texts_autosync_aes_tco);
                } else {
                        hdspm->texts_autosync = texts_autosync_aes;
-                       hdspm->texts_autosync_items = 9;
+                       hdspm->texts_autosync_items =
+                               ARRAY_SIZE(texts_autosync_aes);
                }
                break;