Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 23 Jul 2011 17:59:37 +0000 (10:59 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 23 Jul 2011 17:59:37 +0000 (10:59 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (297 commits)
  ALSA: asihpi - Replace with snd_ctl_boolean_mono_info()
  ALSA: asihpi - HPI version 4.08
  ALSA: asihpi - Add volume mute controls
  ALSA: asihpi - Control name updates
  ALSA: asihpi - Use size_t for sizeof result
  ALSA: asihpi - Explicitly include mutex.h
  ALSA: asihpi - Add new node and message defines
  ALSA: asihpi - Make local function static
  ALSA: asihpi - Fix minor typos and spelling
  ALSA: asihpi - Remove unused structures, macros and functions
  ALSA: asihpi - Remove spurious adapter index check
  ALSA: asihpi - Revise snd_pcm_debug_name, get rid of DEBUG_NAME macro
  ALSA: asihpi - DSP code loader API now independent of OS
  ALSA: asihpi - Remove controlex structs and associated special data transfer code
  ALSA: asihpi - Increase request and response buffer sizes
  ALSA: asihpi - Give more meaningful name to hpi request message type
  ALSA: usb-audio - Add quirk for  Roland / BOSS BR-800
  ALSA: hda - Remove a superfluous argument of via_auto_init_output()
  ALSA: hda - Fix indep-HP path (de-)activation for VT1708* codecs
  ALSA: hda - Add documentation for codec-specific mixer controls
  ...

225 files changed:
Documentation/DocBook/writing-an-alsa-driver.tmpl
Documentation/sound/alsa/HD-Audio-Controls.txt [new file with mode: 0644]
MAINTAINERS
include/linux/pci_ids.h
include/sound/rawmidi.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/trace/events/asoc.h
sound/core/rawmidi.c
sound/firewire/speakers.c
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/asihpi/asihpi.c
sound/pci/asihpi/hpi.h
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpi6205.c
sound/pci/asihpi/hpi6205.h
sound/pci/asihpi/hpi_internal.h
sound/pci/asihpi/hpicmn.c
sound/pci/asihpi/hpidspcd.c
sound/pci/asihpi/hpidspcd.h
sound/pci/asihpi/hpifunc.c
sound/pci/asihpi/hpimsginit.c
sound/pci/asihpi/hpimsgx.c
sound/pci/asihpi/hpioctl.c
sound/pci/asihpi/hpios.c
sound/pci/asihpi/hpios.h
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/aw2/aw2-alsa.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/ctxfi/ct20k2reg.h
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctatc.h
sound/pci/ctxfi/ctdaio.c
sound/pci/ctxfi/ctdaio.h
sound/pci/ctxfi/cthardware.h
sound/pci/ctxfi/cthw20k1.c
sound/pci/ctxfi/cthw20k2.c
sound/pci/ctxfi/ctmixer.c
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/echoaudio.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/alc260_quirks.c [new file with mode: 0644]
sound/pci/hda/alc262_quirks.c [new file with mode: 0644]
sound/pci/hda/alc268_quirks.c [new file with mode: 0644]
sound/pci/hda/alc269_quirks.c [new file with mode: 0644]
sound/pci/hda/alc662_quirks.c [new file with mode: 0644]
sound/pci/hda/alc680_quirks.c [new file with mode: 0644]
sound/pci/hda/alc861_quirks.c [new file with mode: 0644]
sound/pci/hda/alc861vd_quirks.c [new file with mode: 0644]
sound/pci/hda/alc880_quirks.c [new file with mode: 0644]
sound/pci/hda/alc882_quirks.c [new file with mode: 0644]
sound/pci/hda/alc_quirks.c [new file with mode: 0644]
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_ca0132.c [new file with mode: 0644]
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/lola/lola.c
sound/pci/lola/lola.h
sound/pci/lola/lola_mixer.c
sound/pci/lx6464es/lx6464es.c
sound/pci/lx6464es/lx6464es.h
sound/pci/lx6464es/lx_core.c
sound/pci/lx6464es/lx_core.h
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/oxygen_pcm.c
sound/pci/oxygen/virtuoso.c
sound/pci/oxygen/xonar_pcm179x.c
sound/pci/pcxhr/pcxhr.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sis7019.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/trident/trident_main.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/vx/vxpocket.c
sound/soc/Makefile
sound/soc/atmel/atmel-pcm.c
sound/soc/atmel/atmel-pcm.h
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/dbdma2.c
sound/soc/blackfin/Kconfig
sound/soc/blackfin/Makefile
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bf5xx-tdm-pcm.c
sound/soc/blackfin/bfin-eval-adau1701.c [new file with mode: 0644]
sound/soc/blackfin/bfin-eval-adav80x.c [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad1836.h
sound/soc/codecs/adau1701.c [new file with mode: 0644]
sound/soc/codecs/adau1701.h [new file with mode: 0644]
sound/soc/codecs/adav80x.c [new file with mode: 0644]
sound/soc/codecs/adav80x.h [new file with mode: 0644]
sound/soc/codecs/ak4641.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98095.c
sound/soc/codecs/sta32x.c [new file with mode: 0644]
sound/soc/codecs/sta32x.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/wm8782.c [new file with mode: 0644]
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8915.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8983.c [new file with mode: 0644]
sound/soc/codecs/wm8983.h [new file with mode: 0644]
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm_hubs.c
sound/soc/codecs/wm_hubs.h
sound/soc/davinci/davinci-pcm.c
sound/soc/ep93xx/ep93xx-pcm.c
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/fsl/p1022_ds.c
sound/soc/imx/imx-pcm-fiq.c
sound/soc/imx/imx-ssi.c
sound/soc/imx/imx-ssi.h
sound/soc/jz4740/jz4740-pcm.c
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/mid-x86/sst_platform.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/nuc900/nuc900-pcm.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/ams-delta.c
sound/soc/omap/omap-hdmi.c [new file with mode: 0644]
sound/soc/omap/omap-hdmi.h [new file with mode: 0644]
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap4-hdmi-card.c [new file with mode: 0644]
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/s6000/s6000-pcm.c
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/dma.c
sound/soc/samsung/i2s-regs.h [new file with mode: 0644]
sound/soc/samsung/i2s.c
sound/soc/samsung/smdk_wm8994.c
sound/soc/samsung/smdk_wm8994pcm.c [new file with mode: 0644]
sound/soc/samsung/speyside.c
sound/soc/samsung/speyside_wm8962.c [new file with mode: 0644]
sound/soc/sh/dma-sh7760.c
sound/soc/sh/fsi.c
sound/soc/sh/siu_pcm.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-io.c [new file with mode: 0644]
sound/soc/soc-pcm.c [new file with mode: 0644]
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra_i2s.c
sound/soc/tegra/tegra_pcm.c
sound/soc/tegra/tegra_spdif.c [new file with mode: 0644]
sound/soc/tegra/tegra_spdif.h [new file with mode: 0644]
sound/soc/tegra/tegra_wm8903.c
sound/soc/txx9/txx9aclc.c
sound/usb/card.c
sound/usb/endpoint.c
sound/usb/misc/ua101.c
sound/usb/quirks-table.h
sound/usb/quirks.c

index 58ced23..598c22f 100644 (file)
           }
           chip->port = pci_resource_start(pci, 0);
           if (request_irq(pci->irq, snd_mychip_interrupt,
-                          IRQF_SHARED, "My Chip", chip)) {
+                          IRQF_SHARED, KBUILD_MODNAME, chip)) {
                   printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
                   snd_mychip_free(chip);
                   return -EBUSY;
 
   /* pci_driver definition */
   static struct pci_driver driver = {
-          .name = "My Own Chip",
+          .name = KBUILD_MODNAME,
           .id_table = snd_mychip_ids,
           .probe = snd_mychip_probe,
           .remove = __devexit_p(snd_mychip_remove),
           <programlisting>
 <![CDATA[
   if (request_irq(pci->irq, snd_mychip_interrupt,
-                  IRQF_SHARED, "My Chip", chip)) {
+                  IRQF_SHARED, KBUILD_MODNAME, chip)) {
           printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
           snd_mychip_free(chip);
           return -EBUSY;
           <programlisting>
 <![CDATA[
   static struct pci_driver driver = {
-          .name = "My Own Chip",
+          .name = KBUILD_MODNAME,
           .id_table = snd_mychip_ids,
           .probe = snd_mychip_probe,
           .remove = __devexit_p(snd_mychip_remove),
@@ -5816,7 +5816,7 @@ struct _snd_pcm_runtime {
         <programlisting>
 <![CDATA[
   static struct pci_driver driver = {
-          .name = "My Chip",
+          .name = KBUILD_MODNAME,
           .id_table = snd_my_ids,
           .probe = snd_my_probe,
           .remove = __devexit_p(snd_my_remove),
diff --git a/Documentation/sound/alsa/HD-Audio-Controls.txt b/Documentation/sound/alsa/HD-Audio-Controls.txt
new file mode 100644 (file)
index 0000000..1482035
--- /dev/null
@@ -0,0 +1,100 @@
+This file explains the codec-specific mixer controls.
+
+Realtek codecs
+--------------
+
+* Channel Mode
+  This is an enum control to change the surround-channel setup,
+  appears only when the surround channels are available.
+  It gives the number of channels to be used, "2ch", "4ch", "6ch",
+  and "8ch".  According to the configuration, this also controls the
+  jack-retasking of multi-I/O jacks.
+
+* Auto-Mute Mode
+  This is an enum control to change the auto-mute behavior of the
+  headphone and line-out jacks.  If built-in speakers and headphone
+  and/or line-out jacks are available on a machine, this controls
+  appears.
+  When there are only either headphones or line-out jacks, it gives
+  "Disabled" and "Enabled" state.  When enabled, the speaker is muted
+  automatically when a jack is plugged.
+
+  When both headphone and line-out jacks are present, it gives
+  "Disabled", "Speaker Only" and "Line-Out+Speaker".  When
+  speaker-only is chosen, plugging into a headphone or a line-out jack
+  mutes the speakers, but not line-outs.  When line-out+speaker is
+  selected, plugging to a headphone jack mutes both speakers and
+  line-outs.
+
+
+IDT/Sigmatel codecs
+-------------------
+
+* Analog Loopback
+  This control enables/disables the analog-loopback circuit.  This
+  appears only when "loopback" is set to true in a codec hint
+  (see HD-Audio.txt).  Note that on some codecs the analog-loopback
+  and the normal PCM playback are exclusive, i.e. when this is on, you
+  won't hear any PCM stream.
+
+* Swap Center/LFE
+  Swaps the center and LFE channel order.  Normally, the left
+  corresponds to the center and the right to the LFE.  When this is
+  ON, the left to the LFE and the right to the center.
+
+* Headphone as Line Out
+  When this control is ON, treat the headphone jacks as line-out
+  jacks.  That is, the headphone won't auto-mute the other line-outs,
+  and no HP-amp is set to the pins.
+
+* Mic Jack Mode, Line Jack Mode, etc
+  These enum controls the direction and the bias of the input jack
+  pins.  Depending on the jack type, it can set as "Mic In" and "Line 
+  In", for determining the input bias, or it can be set to "Line Out"
+  when the pin is a multi-I/O jack for surround channels.
+
+
+VIA codecs
+----------
+
+* Smart 5.1
+  An enum control to re-task the multi-I/O jacks for surround outputs.
+  When it's ON, the corresponding input jacks (usually a line-in and a
+  mic-in) are switched as the surround and the CLFE output jacks.
+
+* Independent HP
+  When this enum control is enabled, the headphone output is routed
+  from an individual stream (the third PCM such as hw:0,2) instead of
+  the primary stream.  In the case the headphone DAC is shared with a
+  side or a CLFE-channel DAC, the DAC is switched to the headphone
+  automatically.
+
+* Loopback Mixing
+  An enum control to determine whether the analog-loopback route is
+  enabled or not.  When it's enabled, the analog-loopback is mixed to
+  the front-channel.  Also, the same route is used for the headphone
+  and speaker outputs.  As a side-effect, when this mode is set, the
+  individual volume controls will be no longer available for
+  headphones and speakers because there is only one DAC connected to a
+  mixer widget.
+
+* Dynamic Power-Control
+  This control determines whether the dynamic power-control per jack
+  detection is enabled or not.  When enabled, the widgets power state
+  (D0/D3) are changed dynamically depending on the jack plugging
+  state for saving power consumptions.  However, if your system
+  doesn't provide a proper jack-detection, this won't work; in such a
+  case, turn this control OFF.
+
+* Jack Detect
+  This control is provided only for VT1708 codec which gives no proper
+  unsolicited event per jack plug.  When this is on, the driver polls
+  the jack detection so that the headphone auto-mute can work, while 
+  turning this off would reduce the power consumption.
+
+
+Conexant codecs
+---------------
+
+* Auto-Mute Mode
+  See Reatek codecs.
index 41ec646..7521440 100644 (file)
@@ -534,6 +534,8 @@ L:  device-drivers-devel@blackfin.uclinux.org
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://wiki.analog.com/
 S:     Supported
+F:     sound/soc/codecs/adau*
+F:     sound/soc/codecs/adav*
 F:     sound/soc/codecs/ad1*
 F:     sound/soc/codecs/ssm*
 
index 0570930..74173c5 100644 (file)
 #define PCI_SUBDEVICE_ID_CREATIVE_SB08801      0x0041
 #define PCI_SUBDEVICE_ID_CREATIVE_SB08802      0x0042
 #define PCI_SUBDEVICE_ID_CREATIVE_SB08803      0x0043
+#define PCI_SUBDEVICE_ID_CREATIVE_SB1270       0x0062
 #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX      0x6000
 
 #define PCI_VENDOR_ID_ECTIVA           0x1102 /* duplicate: CREATIVE */
index 2480e7d..6b14359 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
+#include <linux/workqueue.h>
 
 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 #include "seq_device.h"
@@ -63,6 +64,7 @@ struct snd_rawmidi_global_ops {
 };
 
 struct snd_rawmidi_runtime {
+       struct snd_rawmidi_substream *substream;
        unsigned int drain: 1,  /* drain stage */
                     oss: 1;    /* OSS compatible mode */
        /* midi stream buffer */
@@ -79,7 +81,7 @@ struct snd_rawmidi_runtime {
        /* event handler (new bytes, input only) */
        void (*event)(struct snd_rawmidi_substream *substream);
        /* defers calls to event [input] or ops->trigger [output] */
-       struct tasklet_struct tasklet;
+       struct work_struct event_work;
        /* private data */
        void *private_data;
        void (*private_free)(struct snd_rawmidi_substream *substream);
index 1bafe95..5ad5f3a 100644 (file)
@@ -209,6 +209,10 @@ struct snd_soc_dai_driver {
        struct snd_soc_pcm_stream capture;
        struct snd_soc_pcm_stream playback;
        unsigned int symmetric_rates:1;
+
+       /* probe ordering - for components with runtime dependencies */
+       int probe_order;
+       int remove_order;
 };
 
 /*
index c46e7d8..e09505c 100644 (file)
@@ -348,6 +348,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
 void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
 int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
                            const struct snd_soc_dapm_route *route, int num);
+int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
+                            const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
 int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
@@ -429,6 +431,7 @@ struct snd_soc_dapm_path {
        /* status */
        u32 connect:1;  /* source and sink widgets are connected */
        u32 walked:1;   /* path has been walked */
+       u32 weak:1;     /* path ignored for power management */
 
        int (*connected)(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink);
@@ -444,6 +447,7 @@ struct snd_soc_dapm_widget {
        char *name;             /* widget name */
        char *sname;    /* stream name */
        struct snd_soc_codec *codec;
+       struct snd_soc_platform *platform;
        struct list_head list;
        struct snd_soc_dapm_context *dapm;
 
@@ -507,10 +511,11 @@ struct snd_soc_dapm_context {
 
        struct device *dev; /* from parent - for debug */
        struct snd_soc_codec *codec; /* parent codec */
+       struct snd_soc_platform *platform; /* parent platform */
        struct snd_soc_card *card; /* parent card */
 
        /* used during DAPM updates */
-       int dev_power;
+       enum snd_soc_bias_level target_bias_level;
        struct list_head list;
 
 #ifdef CONFIG_DEBUG_FS
index 3a4bd3a..aa19f5a 100644 (file)
 #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
        SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
 
+/*
+ * Component probe and remove ordering levels for components with runtime
+ * dependencies.
+ */
+#define SND_SOC_COMP_ORDER_FIRST               -2
+#define SND_SOC_COMP_ORDER_EARLY               -1
+#define SND_SOC_COMP_ORDER_NORMAL              0
+#define SND_SOC_COMP_ORDER_LATE                1
+#define SND_SOC_COMP_ORDER_LAST                2
+
 /*
  * Bias levels
  *
  * @OFF:     Power Off. No restrictions on transition times.
  */
 enum snd_soc_bias_level {
-       SND_SOC_BIAS_OFF,
-       SND_SOC_BIAS_STANDBY,
-       SND_SOC_BIAS_PREPARE,
-       SND_SOC_BIAS_ON,
+       SND_SOC_BIAS_OFF = 0,
+       SND_SOC_BIAS_STANDBY = 1,
+       SND_SOC_BIAS_PREPARE = 2,
+       SND_SOC_BIAS_ON = 3,
 };
 
 struct snd_jack;
@@ -258,6 +268,11 @@ enum snd_soc_compress_type {
        SND_SOC_RBTREE_COMPRESSION
 };
 
+enum snd_soc_pcm_subclass {
+       SND_SOC_PCM_CLASS_PCM   = 0,
+       SND_SOC_PCM_CLASS_BE    = 1,
+};
+
 int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                             unsigned int freq, int dir);
 int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
@@ -297,6 +312,10 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec,
                                      unsigned int reg);
 int snd_soc_default_writable_register(struct snd_soc_codec *codec,
                                      unsigned int reg);
+int snd_soc_platform_read(struct snd_soc_platform *platform,
+                                       unsigned int reg);
+int snd_soc_platform_write(struct snd_soc_platform *platform,
+                                       unsigned int reg, unsigned int val);
 
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
@@ -349,6 +368,8 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
                                  const char *prefix);
 int snd_soc_add_controls(struct snd_soc_codec *codec,
        const struct snd_kcontrol_new *controls, int num_controls);
+int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
+       const struct snd_kcontrol_new *controls, int num_controls);
 int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo);
 int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
@@ -612,6 +633,10 @@ struct snd_soc_codec_driver {
 
        void (*seq_notifier)(struct snd_soc_dapm_context *,
                             enum snd_soc_dapm_type, int);
+
+       /* probe ordering - for components with runtime dependencies */
+       int probe_order;
+       int remove_order;
 };
 
 /* SoC platform interface */
@@ -623,10 +648,17 @@ struct snd_soc_platform_driver {
        int (*resume)(struct snd_soc_dai *dai);
 
        /* pcm creation and destruction */
-       int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
-               struct snd_pcm *);
+       int (*pcm_new)(struct snd_soc_pcm_runtime *);
        void (*pcm_free)(struct snd_pcm *);
 
+       /* Default control and setup, added after probe() is run */
+       const struct snd_kcontrol_new *controls;
+       int num_controls;
+       const struct snd_soc_dapm_widget *dapm_widgets;
+       int num_dapm_widgets;
+       const struct snd_soc_dapm_route *dapm_routes;
+       int num_dapm_routes;
+
        /*
         * For platform caused delay reporting.
         * Optional.
@@ -636,6 +668,14 @@ struct snd_soc_platform_driver {
 
        /* platform stream ops */
        struct snd_pcm_ops *ops;
+
+       /* probe ordering - for components with runtime dependencies */
+       int probe_order;
+       int remove_order;
+
+       /* platform IO - used for platform DAPM */
+       unsigned int (*read)(struct snd_soc_platform *, unsigned int);
+       int (*write)(struct snd_soc_platform *, unsigned int, unsigned int);
 };
 
 struct snd_soc_platform {
@@ -650,6 +690,8 @@ struct snd_soc_platform {
        struct snd_soc_card *card;
        struct list_head list;
        struct list_head card_list;
+
+       struct snd_soc_dapm_context dapm;
 };
 
 struct snd_soc_dai_link {
@@ -725,8 +767,10 @@ struct snd_soc_card {
 
        /* callbacks */
        int (*set_bias_level)(struct snd_soc_card *,
+                             struct snd_soc_dapm_context *dapm,
                              enum snd_soc_bias_level level);
        int (*set_bias_level_post)(struct snd_soc_card *,
+                                  struct snd_soc_dapm_context *dapm,
                                   enum snd_soc_bias_level level);
 
        long pmdown_time;
@@ -789,6 +833,9 @@ struct snd_soc_pcm_runtime  {
        struct device dev;
        struct snd_soc_card *card;
        struct snd_soc_dai_link *dai_link;
+       struct mutex pcm_mutex;
+       enum snd_soc_pcm_subclass pcm_subclass;
+       struct snd_pcm_ops ops;
 
        unsigned int complete:1;
        unsigned int dev_registered:1;
index ae973d2..603f5a0 100644 (file)
@@ -9,6 +9,7 @@
 
 struct snd_soc_jack;
 struct snd_soc_codec;
+struct snd_soc_platform;
 struct snd_soc_card;
 struct snd_soc_dapm_widget;
 
@@ -59,6 +60,50 @@ DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read,
 
 );
 
+DECLARE_EVENT_CLASS(snd_soc_preg,
+
+       TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
+                unsigned int val),
+
+       TP_ARGS(platform, reg, val),
+
+       TP_STRUCT__entry(
+               __string(       name,           platform->name  )
+               __field(        int,            id              )
+               __field(        unsigned int,   reg             )
+               __field(        unsigned int,   val             )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, platform->name);
+               __entry->id = platform->id;
+               __entry->reg = reg;
+               __entry->val = val;
+       ),
+
+       TP_printk("platform=%s.%d reg=%x val=%x", __get_str(name),
+                 (int)__entry->id, (unsigned int)__entry->reg,
+                 (unsigned int)__entry->val)
+);
+
+DEFINE_EVENT(snd_soc_preg, snd_soc_preg_write,
+
+       TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
+                unsigned int val),
+
+       TP_ARGS(platform, reg, val)
+
+);
+
+DEFINE_EVENT(snd_soc_preg, snd_soc_preg_read,
+
+       TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
+                unsigned int val),
+
+       TP_ARGS(platform, reg, val)
+
+);
+
 DECLARE_EVENT_CLASS(snd_soc_card,
 
        TP_PROTO(struct snd_soc_card *card, int val),
index cbbed0d..849a0ed 100644 (file)
@@ -92,16 +92,12 @@ static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substre
               (!substream->append || runtime->avail >= count);
 }
 
-static void snd_rawmidi_input_event_tasklet(unsigned long data)
+static void snd_rawmidi_input_event_work(struct work_struct *work)
 {
-       struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data;
-       substream->runtime->event(substream);
-}
-
-static void snd_rawmidi_output_trigger_tasklet(unsigned long data)
-{
-       struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data;
-       substream->ops->trigger(substream, 1);
+       struct snd_rawmidi_runtime *runtime =
+               container_of(work, struct snd_rawmidi_runtime, event_work);
+       if (runtime->event)
+               runtime->event(runtime->substream);
 }
 
 static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
@@ -110,16 +106,10 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
 
        if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL)
                return -ENOMEM;
+       runtime->substream = substream;
        spin_lock_init(&runtime->lock);
        init_waitqueue_head(&runtime->sleep);
-       if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
-               tasklet_init(&runtime->tasklet,
-                            snd_rawmidi_input_event_tasklet,
-                            (unsigned long)substream);
-       else
-               tasklet_init(&runtime->tasklet,
-                            snd_rawmidi_output_trigger_tasklet,
-                            (unsigned long)substream);
+       INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
        runtime->event = NULL;
        runtime->buffer_size = PAGE_SIZE;
        runtime->avail_min = 1;
@@ -150,12 +140,7 @@ static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *subs
 {
        if (!substream->opened)
                return;
-       if (up) {
-               tasklet_schedule(&substream->runtime->tasklet);
-       } else {
-               tasklet_kill(&substream->runtime->tasklet);
-               substream->ops->trigger(substream, 0);
-       }
+       substream->ops->trigger(substream, up);
 }
 
 static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
@@ -163,8 +148,8 @@ static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, i
        if (!substream->opened)
                return;
        substream->ops->trigger(substream, up);
-       if (!up && substream->runtime->event)
-               tasklet_kill(&substream->runtime->tasklet);
+       if (!up)
+               cancel_work_sync(&substream->runtime->event_work);
 }
 
 int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
@@ -641,10 +626,10 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
                return -EINVAL;
        }
        if (params->buffer_size != runtime->buffer_size) {
-               newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
+               newbuf = krealloc(runtime->buffer, params->buffer_size,
+                                 GFP_KERNEL);
                if (!newbuf)
                        return -ENOMEM;
-               kfree(runtime->buffer);
                runtime->buffer = newbuf;
                runtime->buffer_size = params->buffer_size;
                runtime->avail = runtime->buffer_size;
@@ -668,10 +653,10 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
                return -EINVAL;
        }
        if (params->buffer_size != runtime->buffer_size) {
-               newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
+               newbuf = krealloc(runtime->buffer, params->buffer_size,
+                                 GFP_KERNEL);
                if (!newbuf)
                        return -ENOMEM;
-               kfree(runtime->buffer);
                runtime->buffer = newbuf;
                runtime->buffer_size = params->buffer_size;
        }
@@ -926,7 +911,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
        }
        if (result > 0) {
                if (runtime->event)
-                       tasklet_schedule(&runtime->tasklet);
+                       schedule_work(&runtime->event_work);
                else if (snd_rawmidi_ready(substream))
                        wake_up(&runtime->sleep);
        }
index 5466de8..3fc257d 100644 (file)
@@ -171,7 +171,7 @@ static int fwspk_open(struct snd_pcm_substream *substream)
 
        err = snd_pcm_hw_constraint_minmax(runtime,
                                           SNDRV_PCM_HW_PARAM_PERIOD_TIME,
-                                          5000, 8192000);
+                                          5000, UINT_MAX);
        if (err < 0)
                return err;
 
index d8f6fd6..2015036 100644 (file)
@@ -944,7 +944,7 @@ snd_ad1889_create(struct snd_card *card,
        spin_lock_init(&chip->lock);    /* only now can we call ad1889_free */
 
        if (request_irq(pci->irq, snd_ad1889_interrupt,
-                       IRQF_SHARED, card->driver, chip)) {
+                       IRQF_SHARED, KBUILD_MODNAME, chip)) {
                printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq);
                snd_ad1889_free(chip);
                return -EBUSY;
@@ -1055,7 +1055,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = {
 MODULE_DEVICE_TABLE(pci, snd_ad1889_ids);
 
 static struct pci_driver ad1889_pci_driver = {
-       .name = "AD1889 Audio",
+       .name = KBUILD_MODNAME,
        .id_table = snd_ad1889_ids,
        .probe = snd_ad1889_probe,
        .remove = __devexit_p(snd_ad1889_remove),
index 5c6e322..b444b74 100644 (file)
@@ -2090,7 +2090,7 @@ static int __devinit snd_ali_resources(struct snd_ali *codec)
        codec->port = pci_resource_start(codec->pci, 0);
 
        if (request_irq(codec->pci->irq, snd_ali_card_interrupt,
-                       IRQF_SHARED, "ALI 5451", codec)) {
+                       IRQF_SHARED, KBUILD_MODNAME, codec)) {
                snd_printk(KERN_ERR "Unable to request irq.\n");
                return -EBUSY;
        }
@@ -2295,7 +2295,7 @@ static void __devexit snd_ali_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "ALI 5451",
+       .name = KBUILD_MODNAME,
        .id_table = snd_ali_ids,
        .probe = snd_ali_probe,
        .remove = __devexit_p(snd_ali_remove),
index d7653cb..736c8e9 100644 (file)
@@ -722,7 +722,7 @@ static int __devinit snd_als300_create(struct snd_card *card,
                irq_handler = snd_als300_interrupt;
 
        if (request_irq(pci->irq, irq_handler, IRQF_SHARED,
-                       card->shortname, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_als300_free(chip);
                return -EBUSY;
@@ -846,7 +846,7 @@ static int __devinit snd_als300_probe(struct pci_dev *pci,
 }
 
 static struct pci_driver driver = {
-       .name = "ALS300",
+       .name = KBUILD_MODNAME,
        .id_table = snd_als300_ids,
        .probe = snd_als300_probe,
        .remove = __devexit_p(snd_als300_remove),
index 0e247cb..a9c1af3 100644 (file)
@@ -1036,7 +1036,7 @@ static int snd_als4000_resume(struct pci_dev *pci)
 
 
 static struct pci_driver driver = {
-       .name = "ALS4000",
+       .name = KBUILD_MODNAME,
        .id_table = snd_als4000_ids,
        .probe = snd_card_als4000_probe,
        .remove = __devexit_p(snd_card_als4000_remove),
index e3569bd..b941d25 100644 (file)
@@ -49,19 +49,21 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 #if defined CONFIG_SND_DEBUG
 /* copied from pcm_lib.c, hope later patch will make that version public
 and this copy can be removed */
-static void pcm_debug_name(struct snd_pcm_substream *substream,
-                          char *name, size_t len)
+static inline void
+snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
 {
-       snprintf(name, len, "pcmC%dD%d%c:%d",
+       snprintf(buf, size, "pcmC%dD%d%c:%d",
                 substream->pcm->card->number,
                 substream->pcm->device,
                 substream->stream ? 'c' : 'p',
                 substream->number);
 }
-#define DEBUG_NAME(substream, name) char name[16]; pcm_debug_name(substream, name, sizeof(name))
 #else
-#define pcm_debug_name(s, n, l) do { } while (0)
-#define DEBUG_NAME(name, substream) do { } while (0)
+static inline void
+snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
+{
+       *buf = 0;
+}
 #endif
 
 #if defined CONFIG_SND_DEBUG_VERBOSE
@@ -304,7 +306,8 @@ static u16 handle_error(u16 err, int line, char *filename)
 static void print_hwparams(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *p)
 {
-       DEBUG_NAME(substream, name);
+       char name[16];
+       snd_pcm_debug_name(substream, name, sizeof(name));
        snd_printd("%s HWPARAMS\n", name);
        snd_printd(" samplerate %d Hz\n", params_rate(p));
        snd_printd(" channels %d\n", params_channels(p));
@@ -576,8 +579,9 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
        struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
        struct snd_pcm_substream *s;
        u16 e;
-       DEBUG_NAME(substream, name);
+       char name[16];
 
+       snd_pcm_debug_name(substream, name, sizeof(name));
        snd_printdd("%s trigger\n", name);
 
        switch (cmd) {
@@ -741,7 +745,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
        int loops = 0;
        u16 state;
        u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
-       DEBUG_NAME(substream, name);
+       char name[16];
+
+       snd_pcm_debug_name(substream, name, sizeof(name));
 
        snd_printdd("%s snd_card_asihpi_timer_function\n", name);
 
@@ -1323,10 +1329,12 @@ static const char * const asihpi_src_names[] = {
        "RF",
        "Clock",
        "Bitstream",
-       "Microphone",
-       "Cobranet",
+       "Mic",
+       "Net",
        "Analog",
        "Adapter",
+       "RTP",
+       "GPI",
 };
 
 compile_time_assert(
@@ -1341,8 +1349,10 @@ static const char * const asihpi_dst_names[] = {
        "Digital",
        "RF",
        "Speaker",
-       "Cobranet Out",
-       "Analog"
+       "Net",
+       "Analog",
+       "RTP",
+       "GPO",
 };
 
 compile_time_assert(
@@ -1476,11 +1486,40 @@ static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
 
 static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
 
+#define snd_asihpi_volume_mute_info    snd_ctl_boolean_mono_info
+
+static int snd_asihpi_volume_mute_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       u32 h_control = kcontrol->private_value;
+       u32 mute;
+
+       hpi_handle_error(hpi_volume_get_mute(h_control, &mute));
+       ucontrol->value.integer.value[0] = mute ? 0 : 1;
+
+       return 0;
+}
+
+static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       u32 h_control = kcontrol->private_value;
+       int change = 1;
+       /* HPI currently only supports all or none muting of multichannel volume
+       ALSA Switch element has opposite sense to HPI mute: on==unmuted, off=muted
+       */
+       int mute =  ucontrol->value.integer.value[0] ? 0 : HPI_BITMASK_ALL_CHANNELS;
+       hpi_handle_error(hpi_volume_set_mute(h_control, mute));
+       return change;
+}
+
 static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
                                        struct hpi_control *hpi_ctl)
 {
        struct snd_card *card = asihpi->card;
        struct snd_kcontrol_new snd_control;
+       int err;
+       u32 mute;
 
        asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");
        snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
@@ -1490,7 +1529,19 @@ static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
        snd_control.put = snd_asihpi_volume_put;
        snd_control.tlv.p = db_scale_100;
 
-       return ctl_add(card, &snd_control, asihpi);
+       err = ctl_add(card, &snd_control, asihpi);
+       if (err)
+               return err;
+
+       if (hpi_volume_get_mute(hpi_ctl->h_control, &mute) == 0) {
+               asihpi_ctl_init(&snd_control, hpi_ctl, "Switch");
+               snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+               snd_control.info = snd_asihpi_volume_mute_info;
+               snd_control.get = snd_asihpi_volume_mute_get;
+               snd_control.put = snd_asihpi_volume_mute_put;
+               err = ctl_add(card, &snd_control, asihpi);
+       }
+       return err;
 }
 
 /*------------------------------------------------------------
@@ -2923,7 +2974,7 @@ static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = {
 MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
 
 static struct pci_driver driver = {
-       .name = "asihpi",
+       .name = KBUILD_MODNAME,
        .id_table = asihpi_pci_tbl,
        .probe = snd_asihpi_probe,
        .remove = __devexit_p(snd_asihpi_remove),
index 255429c..f207272 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
@@ -42,12 +42,11 @@ i.e 3.05.02 is a development version
 #define HPI_VER_MINOR(v) ((int)((v >> 8) & 0xFF))
 #define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
 
-/* Use single digits for versions less that 10 to avoid octal. */
-#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 6, 0)
-#define HPI_VER_STRING "4.06.00"
+#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 8, 0)
+#define HPI_VER_STRING "4.08.00"
 
 /* Library version as documented in hpi-api-versions.txt */
-#define HPI_LIB_VER  HPI_VERSION_CONSTRUCTOR(9, 0, 0)
+#define HPI_LIB_VER  HPI_VERSION_CONSTRUCTOR(10, 0, 0)
 
 #include <linux/types.h>
 #define HPI_BUILD_EXCLUDE_DEPRECATED
@@ -211,8 +210,12 @@ enum HPI_SOURCENODES {
        HPI_SOURCENODE_COBRANET = 109,
        HPI_SOURCENODE_ANALOG = 110,         /**< analog input node. */
        HPI_SOURCENODE_ADAPTER = 111,        /**< adapter node. */
+       /** RTP stream input node - This node is a destination for
+           packets of RTP audio samples from other devices. */
+       HPI_SOURCENODE_RTP_DESTINATION = 112,
+       HPI_SOURCENODE_GP_IN = 113,          /**< general purpose input. */
        /* !!!Update this  AND hpidebug.h if you add a new sourcenode type!!! */
-       HPI_SOURCENODE_LAST_INDEX = 111      /**< largest ID */
+       HPI_SOURCENODE_LAST_INDEX = 113      /**< largest ID */
                /* AX6 max sourcenode types = 15 */
 };
 
@@ -228,7 +231,7 @@ enum HPI_DESTNODES {
        HPI_DESTNODE_NONE = 200,
        /** In Stream (Record) node. */
        HPI_DESTNODE_ISTREAM = 201,
-       HPI_DESTNODE_LINEOUT = 202,         /**< line out node. */
+       HPI_DESTNODE_LINEOUT = 202,          /**< line out node. */
        HPI_DESTNODE_AESEBU_OUT = 203,       /**< AES/EBU output node. */
        HPI_DESTNODE_RF = 204,               /**< RF output node. */
        HPI_DESTNODE_SPEAKER = 205,          /**< speaker output node. */
@@ -236,9 +239,12 @@ enum HPI_DESTNODES {
            Audio samples from the device are sent out on the Cobranet network.*/
        HPI_DESTNODE_COBRANET = 206,
        HPI_DESTNODE_ANALOG = 207,           /**< analog output node. */
-
+       /** RTP stream output node - This node is a source for
+           packets of RTP audio samples that are sent to other devices. */
+       HPI_DESTNODE_RTP_SOURCE = 208,
+       HPI_DESTNODE_GP_OUT = 209,           /**< general purpose output node. */
        /* !!!Update this AND hpidebug.h if you add a new destnode type!!! */
-       HPI_DESTNODE_LAST_INDEX = 207        /**< largest ID */
+       HPI_DESTNODE_LAST_INDEX = 209        /**< largest ID */
                /* AX6 max destnode types = 15 */
 };
 
index df4aed5..3cc6f11 100644 (file)
@@ -359,7 +359,7 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
                        HPI_ERROR_PROCESSING_MESSAGE);
 
        switch (phm->type) {
-       case HPI_TYPE_MESSAGE:
+       case HPI_TYPE_REQUEST:
                switch (phm->object) {
                case HPI_OBJ_SUBSYSTEM:
                        subsys_message(phm, phr);
@@ -538,7 +538,7 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
 
                HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n");
                memset(&hm, 0, sizeof(hm));
-               hm.type = HPI_TYPE_MESSAGE;
+               hm.type = HPI_TYPE_REQUEST;
                hm.size = sizeof(struct hpi_message);
                hm.object = HPI_OBJ_ADAPTER;
                hm.function = HPI_ADAPTER_GET_INFO;
@@ -946,11 +946,8 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
                }
 
                /* write the DSP code down into the DSPs memory */
-               /*HpiDspCode_Open(nBootLoadFamily,&DspCode,pdwOsErrorCode); */
-               dsp_code.ps_dev = pao->pci.pci_dev;
-
-               error = hpi_dsp_code_open(boot_load_family, &dsp_code,
-                       pos_error_code);
+               error = hpi_dsp_code_open(boot_load_family, pao->pci.pci_dev,
+                       &dsp_code, pos_error_code);
 
                if (error)
                        return error;
index 9d5df54..e041a6a 100644 (file)
@@ -373,6 +373,7 @@ static void instream_message(struct hpi_adapter_obj *pao,
 /** Entry point to this HPI backend
  * All calls to the HPI start here
  */
+static
 void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
        struct hpi_response *phr)
 {
@@ -392,7 +393,7 @@ void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
 
        HPI_DEBUG_LOG(VERBOSE, "start of switch\n");
        switch (phm->type) {
-       case HPI_TYPE_MESSAGE:
+       case HPI_TYPE_REQUEST:
                switch (phm->object) {
                case HPI_OBJ_SUBSYSTEM:
                        subsys_message(pao, phm, phr);
@@ -402,7 +403,6 @@ void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
                        adapter_message(pao, phm, phr);
                        break;
 
-               case HPI_OBJ_CONTROLEX:
                case HPI_OBJ_CONTROL:
                        control_message(pao, phm, phr);
                        break;
@@ -634,11 +634,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 
                HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n");
                memset(&hm, 0, sizeof(hm));
-               hm.type = HPI_TYPE_MESSAGE;
+               /* wAdapterIndex == version == 0 */
+               hm.type = HPI_TYPE_REQUEST;
                hm.size = sizeof(hm);
                hm.object = HPI_OBJ_ADAPTER;
                hm.function = HPI_ADAPTER_GET_INFO;
-               hm.adapter_index = 0;
+
                memset(&hr, 0, sizeof(hr));
                hr.size = sizeof(hr);
 
@@ -658,9 +659,6 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
                        hr.u.ax.info.num_outstreams +
                        hr.u.ax.info.num_instreams;
 
-               hpios_locked_mem_prepare((max_streams * 6) / 10, max_streams,
-                       65536, pao->pci.pci_dev);
-
                HPI_DEBUG_LOG(VERBOSE,
                        "got adapter info type %x index %d serial %d\n",
                        hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index,
@@ -709,9 +707,6 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao)
                                [i]);
                        phw->outstream_host_buffer_size[i] = 0;
                }
-
-       hpios_locked_mem_unprepare(pao->pci.pci_dev);
-
        kfree(phw);
 }
 
@@ -1371,9 +1366,8 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
                        return err;
 
                /* write the DSP code down into the DSPs memory */
-               dsp_code.ps_dev = pao->pci.pci_dev;
-               err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code,
-                       pos_error_code);
+               err = hpi_dsp_code_open(boot_code_id[dsp], pao->pci.pci_dev,
+                       &dsp_code, pos_error_code);
                if (err)
                        return err;
 
@@ -2084,13 +2078,13 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao,
        u16 err = 0;
 
        message_count++;
-       if (phm->size > sizeof(interface->u)) {
+       if (phm->size > sizeof(interface->u.message_buffer)) {
                phr->error = HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL;
-               phr->specific_error = sizeof(interface->u);
+               phr->specific_error = sizeof(interface->u.message_buffer);
                phr->size = sizeof(struct hpi_response_header);
                HPI_DEBUG_LOG(ERROR,
                        "message len %d too big for buffer %zd \n", phm->size,
-                       sizeof(interface->u));
+                       sizeof(interface->u.message_buffer));
                return 0;
        }
 
@@ -2122,18 +2116,19 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao,
 
        /* read the result */
        if (time_out) {
-               if (interface->u.response_buffer.size <= phr->size)
+               if (interface->u.response_buffer.response.size <= phr->size)
                        memcpy(phr, &interface->u.response_buffer,
-                               interface->u.response_buffer.size);
+                               interface->u.response_buffer.response.size);
                else {
                        HPI_DEBUG_LOG(ERROR,
                                "response len %d too big for buffer %d\n",
-                               interface->u.response_buffer.size, phr->size);
+                               interface->u.response_buffer.response.size,
+                               phr->size);
                        memcpy(phr, &interface->u.response_buffer,
                                sizeof(struct hpi_response_header));
                        phr->error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
                        phr->specific_error =
-                               interface->u.response_buffer.size;
+                               interface->u.response_buffer.response.size;
                        phr->size = sizeof(struct hpi_response_header);
                }
        }
@@ -2202,23 +2197,6 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
                        phm->u.d.u.data.data_size, H620_HIF_GET_DATA);
                break;
 
-       case HPI_CONTROL_SET_STATE:
-               if (phm->object == HPI_OBJ_CONTROLEX
-                       && phm->u.cx.attribute == HPI_COBRANET_SET_DATA)
-                       err = hpi6205_transfer_data(pao,
-                               phm->u.cx.u.cobranet_bigdata.pb_data,
-                               phm->u.cx.u.cobranet_bigdata.byte_count,
-                               H620_HIF_SEND_DATA);
-               break;
-
-       case HPI_CONTROL_GET_STATE:
-               if (phm->object == HPI_OBJ_CONTROLEX
-                       && phm->u.cx.attribute == HPI_COBRANET_GET_DATA)
-                       err = hpi6205_transfer_data(pao,
-                               phm->u.cx.u.cobranet_bigdata.pb_data,
-                               phr->u.cx.u.cobranet_data.byte_count,
-                               H620_HIF_GET_DATA);
-               break;
        }
        phr->error = err;
 
index df2f02c..ec0827b 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
@@ -70,15 +70,28 @@ The Host located memory buffer that the 6205 will bus master
 in and out of.
 ************************************************************/
 #define HPI6205_SIZEOF_DATA (16*1024)
+
+struct message_buffer_6205 {
+       struct hpi_message message;
+       char data[256];
+};
+
+struct response_buffer_6205 {
+       struct hpi_response response;
+       char data[256];
+};
+
+union buffer_6205 {
+       struct message_buffer_6205 message_buffer;
+       struct response_buffer_6205 response_buffer;
+       u8 b_data[HPI6205_SIZEOF_DATA];
+};
+
 struct bus_master_interface {
        u32 host_cmd;
        u32 dsp_ack;
        u32 transfer_size_in_bytes;
-       union {
-               struct hpi_message_header message_buffer;
-               struct hpi_response_header response_buffer;
-               u8 b_data[HPI6205_SIZEOF_DATA];
-       } u;
+       union buffer_6205 u;
        struct controlcache_6205 control_cache;
        struct async_event_buffer_6205 async_buffer;
        struct hpi_hostbuffer_status
index bf5eced..d497030 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
@@ -32,12 +32,6 @@ HPI internal definitions
 #include "hpios.h"
 
 /* physical memory allocation */
-void hpios_locked_mem_init(void
-       );
-void hpios_locked_mem_free_all(void
-       );
-#define hpios_locked_mem_prepare(a, b, c, d);
-#define hpios_locked_mem_unprepare(a)
 
 /** Allocate and map an area of locked memory for bus master DMA operations.
 
@@ -226,8 +220,8 @@ enum HPI_CONTROL_ATTRIBUTES {
 
        HPI_COBRANET_SET = HPI_CTL_ATTR(COBRANET, 1),
        HPI_COBRANET_GET = HPI_CTL_ATTR(COBRANET, 2),
-       HPI_COBRANET_SET_DATA = HPI_CTL_ATTR(COBRANET, 3),
-       HPI_COBRANET_GET_DATA = HPI_CTL_ATTR(COBRANET, 4),
+       /*HPI_COBRANET_SET_DATA         = HPI_CTL_ATTR(COBRANET, 3), */
+       /*HPI_COBRANET_GET_DATA         = HPI_CTL_ATTR(COBRANET, 4), */
        HPI_COBRANET_GET_STATUS = HPI_CTL_ATTR(COBRANET, 5),
        HPI_COBRANET_SEND_PACKET = HPI_CTL_ATTR(COBRANET, 6),
        HPI_COBRANET_GET_PACKET = HPI_CTL_ATTR(COBRANET, 7),
@@ -364,10 +358,12 @@ Used in DLL to indicate device not present
 #define HPI_ADAPTER_ASI(f)   (f)
 
 enum HPI_MESSAGE_TYPES {
-       HPI_TYPE_MESSAGE = 1,
+       HPI_TYPE_REQUEST = 1,
        HPI_TYPE_RESPONSE = 2,
        HPI_TYPE_DATA = 3,
-       HPI_TYPE_SSX2BYPASS_MESSAGE = 4
+       HPI_TYPE_SSX2BYPASS_MESSAGE = 4,
+       HPI_TYPE_COMMAND = 5,
+       HPI_TYPE_NOTIFICATION = 6
 };
 
 enum HPI_OBJECT_TYPES {
@@ -383,7 +379,7 @@ enum HPI_OBJECT_TYPES {
        HPI_OBJ_WATCHDOG = 10,
        HPI_OBJ_CLOCK = 11,
        HPI_OBJ_PROFILE = 12,
-       HPI_OBJ_CONTROLEX = 13,
+       /* HPI_ OBJ_ CONTROLEX  = 13, */
        HPI_OBJ_ASYNCEVENT = 14
 #define HPI_OBJ_MAXINDEX 14
 };
@@ -608,7 +604,7 @@ struct hpi_data_compat32 {
 #endif
 
 struct hpi_buffer {
-  /** placehoder for backward compatibility (see dwBufferSize) */
+  /** placeholder for backward compatibility (see dwBufferSize) */
        struct hpi_msg_format reserved;
        u32 command; /**< HPI_BUFFER_CMD_xxx*/
        u32 pci_address; /**< PCI physical address of buffer for DSP DMA */
@@ -912,95 +908,13 @@ union hpi_control_union_res {
                u32 remaining_chars;
        } chars8;
        char c_data12[12];
-};
-
-/* HPI_CONTROLX_STRUCTURES */
-
-/* Message */
-
-/** Used for all HMI variables where max length <= 8 bytes
-*/
-struct hpi_controlx_msg_cobranet_data {
-       u32 hmi_address;
-       u32 byte_count;
-       u32 data[2];
-};
-
-/** Used for string data, and for packet bridge
-*/
-struct hpi_controlx_msg_cobranet_bigdata {
-       u32 hmi_address;
-       u32 byte_count;
-       u8 *pb_data;
-#ifndef HPI64BIT
-       u32 padding;
-#endif
-};
-
-/** Used for PADS control reading of string fields.
-*/
-struct hpi_controlx_msg_pad_data {
-       u32 field;
-       u32 byte_count;
-       u8 *pb_data;
-#ifndef HPI64BIT
-       u32 padding;
-#endif
-};
-
-/** Used for generic data
-*/
-
-struct hpi_controlx_msg_generic {
-       u32 param1;
-       u32 param2;
-};
-
-struct hpi_controlx_msg {
-       u16 attribute;          /* control attribute or property */
-       u16 saved_index;
-       union {
-               struct hpi_controlx_msg_cobranet_data cobranet_data;
-               struct hpi_controlx_msg_cobranet_bigdata cobranet_bigdata;
-               struct hpi_controlx_msg_generic generic;
-               struct hpi_controlx_msg_pad_data pad_data;
-               /*struct param_value universal_value; */
-               /* nothing extra to send for status read */
-       } u;
-};
-
-/* Response */
-/**
-*/
-struct hpi_controlx_res_cobranet_data {
-       u32 byte_count;
-       u32 data[2];
-};
-
-struct hpi_controlx_res_cobranet_bigdata {
-       u32 byte_count;
-};
-
-struct hpi_controlx_res_cobranet_status {
-       u32 status;
-       u32 readable_size;
-       u32 writeable_size;
-};
-
-struct hpi_controlx_res_generic {
-       u32 param1;
-       u32 param2;
-};
-
-struct hpi_controlx_res {
        union {
-               struct hpi_controlx_res_cobranet_bigdata cobranet_bigdata;
-               struct hpi_controlx_res_cobranet_data cobranet_data;
-               struct hpi_controlx_res_cobranet_status cobranet_status;
-               struct hpi_controlx_res_generic generic;
-               /*struct param_info universal_info; */
-               /*struct param_value universal_value; */
-       } u;
+               struct {
+                       u32 status;
+                       u32 readable_size;
+                       u32 writeable_size;
+               } status;
+       } cobranet;
 };
 
 struct hpi_nvmemory_msg {
@@ -1126,7 +1040,6 @@ struct hpi_message {
                /* identical to struct hpi_control_msg,
                   but field naming is improved */
                struct hpi_control_union_msg cu;
-               struct hpi_controlx_msg cx;     /* extended mixer control; */
                struct hpi_nvmemory_msg n;
                struct hpi_gpio_msg l;  /* digital i/o */
                struct hpi_watchdog_msg w;
@@ -1151,7 +1064,7 @@ struct hpi_message {
        sizeof(struct hpi_message_header) + sizeof(struct hpi_watchdog_msg),\
        sizeof(struct hpi_message_header) + sizeof(struct hpi_clock_msg),\
        sizeof(struct hpi_message_header) + sizeof(struct hpi_profile_msg),\
-       sizeof(struct hpi_message_header) + sizeof(struct hpi_controlx_msg),\
+       sizeof(struct hpi_message_header), /* controlx obj removed */ \
        sizeof(struct hpi_message_header) + sizeof(struct hpi_async_msg) \
 }
 
@@ -1188,7 +1101,6 @@ struct hpi_response {
                struct hpi_control_res c;       /* mixer control; */
                /* identical to hpi_control_res, but field naming is improved */
                union hpi_control_union_res cu;
-               struct hpi_controlx_res cx;     /* extended mixer control; */
                struct hpi_nvmemory_res n;
                struct hpi_gpio_res l;  /* digital i/o */
                struct hpi_watchdog_res w;
@@ -1213,7 +1125,7 @@ struct hpi_response {
        sizeof(struct hpi_response_header) + sizeof(struct hpi_watchdog_res),\
        sizeof(struct hpi_response_header) + sizeof(struct hpi_clock_res),\
        sizeof(struct hpi_response_header) + sizeof(struct hpi_profile_res),\
-       sizeof(struct hpi_response_header) + sizeof(struct hpi_controlx_res),\
+       sizeof(struct hpi_response_header), /* controlx obj removed */ \
        sizeof(struct hpi_response_header) + sizeof(struct hpi_async_res) \
 }
 
@@ -1308,6 +1220,30 @@ struct hpi_res_adapter_debug_read {
        u8 bytes[256];
 };
 
+struct hpi_msg_cobranet_hmi {
+       u16 attribute;
+       u16 padding;
+       u32 hmi_address;
+       u32 byte_count;
+};
+
+struct hpi_msg_cobranet_hmiwrite {
+       struct hpi_message_header h;
+       struct hpi_msg_cobranet_hmi p;
+       u8 bytes[256];
+};
+
+struct hpi_msg_cobranet_hmiread {
+       struct hpi_message_header h;
+       struct hpi_msg_cobranet_hmi p;
+};
+
+struct hpi_res_cobranet_hmiread {
+       struct hpi_response_header h;
+       u32 byte_count;
+       u8 bytes[256];
+};
+
 #if 1
 #define hpi_message_header_v1 hpi_message_header
 #define hpi_response_header_v1 hpi_response_header
@@ -1338,7 +1274,6 @@ struct hpi_msg_payload_v0 {
                union hpi_mixerx_msg mx;
                struct hpi_control_msg c;
                struct hpi_control_union_msg cu;
-               struct hpi_controlx_msg cx;
                struct hpi_nvmemory_msg n;
                struct hpi_gpio_msg l;
                struct hpi_watchdog_msg w;
@@ -1358,7 +1293,6 @@ struct hpi_res_payload_v0 {
                union hpi_mixerx_res mx;
                struct hpi_control_res c;
                union hpi_control_union_res cu;
-               struct hpi_controlx_res cx;
                struct hpi_nvmemory_res n;
                struct hpi_gpio_res l;
                struct hpi_watchdog_res w;
@@ -1493,12 +1427,6 @@ struct hpi_control_cache_microphone {
        char temp_padding[6];
 };
 
-struct hpi_control_cache_generic {
-       struct hpi_control_cache_info i;
-       u32 dw1;
-       u32 dw2;
-};
-
 struct hpi_control_cache_single {
        union {
                struct hpi_control_cache_info i;
@@ -1514,7 +1442,6 @@ struct hpi_control_cache_single {
                struct hpi_control_cache_silencedetector silence;
                struct hpi_control_cache_sampleclock clk;
                struct hpi_control_cache_microphone microphone;
-               struct hpi_control_cache_generic generic;
        } u;
 };
 
index b15a02e..65b7ca1 100644 (file)
@@ -57,7 +57,7 @@ u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
        }
 
        if (phr->function != phm->function) {
-               HPI_DEBUG_LOG(ERROR, "header type %d invalid\n",
+               HPI_DEBUG_LOG(ERROR, "header function %d invalid\n",
                        phr->function);
                return HPI_ERROR_INVALID_RESPONSE;
        }
@@ -315,8 +315,7 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
        short found = 1;
        struct hpi_control_cache_info *pI;
        struct hpi_control_cache_single *pC;
-       struct hpi_control_cache_pad *p_pad;
-
+       size_t response_size;
        if (!find_control(phm->obj_index, p_cache, &pI)) {
                HPI_DEBUG_LOG(VERBOSE,
                        "HPICMN find_control() failed for adap %d\n",
@@ -326,11 +325,15 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
 
        phr->error = 0;
 
+       /* set the default response size */
+       response_size =
+               sizeof(struct hpi_response_header) +
+               sizeof(struct hpi_control_res);
+
        /* pC is the default cached control strucure. May be cast to
           something else in the following switch statement.
         */
        pC = (struct hpi_control_cache_single *)pI;
-       p_pad = (struct hpi_control_cache_pad *)pI;
 
        switch (pI->control_type) {
 
@@ -529,9 +532,7 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
                pI->control_index, pI->control_type, phm->u.c.attribute);
 
        if (found)
-               phr->size =
-                       sizeof(struct hpi_response_header) +
-                       sizeof(struct hpi_control_res);
+               phr->size = (u16)response_size;
 
        return found;
 }
@@ -682,7 +683,7 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
 void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
 {
        switch (phm->type) {
-       case HPI_TYPE_MESSAGE:
+       case HPI_TYPE_REQUEST:
                switch (phm->object) {
                case HPI_OBJ_SUBSYSTEM:
                        subsys_message(phm, phr);
index 5c6ea11..3a7afa3 100644 (file)
@@ -1,8 +1,8 @@
 /***********************************************************************/
-/*!
+/**
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 \file
-Functions for reading DSP code to load into DSP
-
-(Linux only:) If DSPCODE_FIRMWARE_LOADER is defined, code is read using
+Functions for reading DSP code using
 hotplug firmware loader from individual dsp code files
-
-If neither of the above is defined, code is read from linked arrays.
-DSPCODE_ARRAY is defined.
-
-HPI_INCLUDE_**** must be defined
-and the appropriate hzz?????.c or hex?????.c linked in
-
- */
+*/
 /***********************************************************************/
 #define SOURCEFILE_NAME "hpidspcd.c"
 #include "hpidspcd.h"
 #include "hpidebug.h"
 
-/**
- Header structure for binary dsp code file (see asidsp.doc)
- This structure must match that used in s2bin.c for generation of asidsp.bin
- */
-
-#ifndef DISABLE_PRAGMA_PACK1
-#pragma pack(push, 1)
-#endif
-
-struct code_header {
-       u32 size;
-       char type[4];
-       u32 adapter;
-       u32 version;
-       u32 crc;
+struct dsp_code_private {
+       /**  Firmware descriptor */
+       const struct firmware *firmware;
+       struct pci_dev *dev;
 };
 
-#ifndef DISABLE_PRAGMA_PACK1
-#pragma pack(pop)
-#endif
-
 #define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \
            HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
 
-/***********************************************************************/
-#include <linux/pci.h>
 /*-------------------------------------------------------------------*/
-short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code,
-       u32 *pos_error_code)
+short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
+       u32 *os_error_code)
 {
-       const struct firmware *ps_firmware = ps_dsp_code->ps_firmware;
+       const struct firmware *firmware;
+       struct pci_dev *dev = os_data;
        struct code_header header;
        char fw_name[20];
        int err;
 
        sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
 
-       err = request_firmware(&ps_firmware, fw_name,
-               &ps_dsp_code->ps_dev->dev);
+       err = request_firmware(&firmware, fw_name, &dev->dev);
 
-       if (err != 0) {
-               dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
+       if (err || !firmware) {
+               dev_printk(KERN_ERR, &dev->dev,
                        "%d, request_firmware failed for  %s\n", err,
                        fw_name);
                goto error1;
        }
-       if (ps_firmware->size < sizeof(header)) {
-               dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
-                       "Header size too small %s\n", fw_name);
-               goto error2;
-       }
-       memcpy(&header, ps_firmware->data, sizeof(header));
-       if (header.adapter != adapter) {
-               dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
-                       "Adapter type incorrect %4x != %4x\n", header.adapter,
-                       adapter);
+       if (firmware->size < sizeof(header)) {
+               dev_printk(KERN_ERR, &dev->dev, "Header size too small %s\n",
+                       fw_name);
                goto error2;
        }
-       if (header.size != ps_firmware->size) {
-               dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
-                       "Code size wrong  %d != %ld\n", header.size,
-                       (unsigned long)ps_firmware->size);
+       memcpy(&header, firmware->data, sizeof(header));
+
+       if ((header.type != 0x45444F43) ||      /* "CODE" */
+               (header.adapter != adapter)
+               || (header.size != firmware->size)) {
+               dev_printk(KERN_ERR, &dev->dev, "Invalid firmware file\n");
                goto error2;
        }
 
-       if (header.version / 100 != HPI_VER_DECIMAL / 100) {
-               dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
+       if ((header.version / 100 & ~1) != (HPI_VER_DECIMAL / 100 & ~1)) {
+               dev_printk(KERN_ERR, &dev->dev,
                        "Incompatible firmware version "
                        "DSP image %d != Driver %d\n", header.version,
                        HPI_VER_DECIMAL);
@@ -109,67 +78,70 @@ short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code,
        }
 
        if (header.version != HPI_VER_DECIMAL) {
-               dev_printk(KERN_WARNING, &ps_dsp_code->ps_dev->dev,
+               dev_printk(KERN_WARNING, &dev->dev,
                        "Firmware: release version mismatch  DSP image %d != Driver %d\n",
                        header.version, HPI_VER_DECIMAL);
        }
 
        HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name);
-       ps_dsp_code->ps_firmware = ps_firmware;
-       ps_dsp_code->block_length = header.size / sizeof(u32);
-       ps_dsp_code->word_count = sizeof(header) / sizeof(u32);
-       ps_dsp_code->version = header.version;
-       ps_dsp_code->crc = header.crc;
+       dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL);
+       if (!dsp_code->pvt)
+               return HPI_ERROR_MEMORY_ALLOC;
+
+       dsp_code->pvt->dev = dev;
+       dsp_code->pvt->firmware = firmware;
+       dsp_code->header = header;
+       dsp_code->block_length = header.size / sizeof(u32);
+       dsp_code->word_count = sizeof(header) / sizeof(u32);
        return 0;
 
 error2:
-       release_firmware(ps_firmware);
+       release_firmware(firmware);
 error1:
-       ps_dsp_code->ps_firmware = NULL;
-       ps_dsp_code->block_length = 0;
+       dsp_code->block_length = 0;
        return HPI_ERROR_DSP_FILE_NOT_FOUND;
 }
 
 /*-------------------------------------------------------------------*/
-void hpi_dsp_code_close(struct dsp_code *ps_dsp_code)
+void hpi_dsp_code_close(struct dsp_code *dsp_code)
 {
-       if (ps_dsp_code->ps_firmware != NULL) {
+       if (dsp_code->pvt->firmware) {
                HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
-               release_firmware(ps_dsp_code->ps_firmware);
-               ps_dsp_code->ps_firmware = NULL;
+               release_firmware(dsp_code->pvt->firmware);
+               dsp_code->pvt->firmware = NULL;
        }
+       kfree(dsp_code->pvt);
 }
 
 /*-------------------------------------------------------------------*/
-void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code)
+void hpi_dsp_code_rewind(struct dsp_code *dsp_code)
 {
        /* Go back to start of  data, after header */
-       ps_dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
+       dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
 }
 
 /*-------------------------------------------------------------------*/
-short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, u32 *pword)
+short hpi_dsp_code_read_word(struct dsp_code *dsp_code, u32 *pword)
 {
-       if (ps_dsp_code->word_count + 1 > ps_dsp_code->block_length)
+       if (dsp_code->word_count + 1 > dsp_code->block_length)
                return HPI_ERROR_DSP_FILE_FORMAT;
 
-       *pword = ((u32 *)(ps_dsp_code->ps_firmware->data))[ps_dsp_code->
+       *pword = ((u32 *)(dsp_code->pvt->firmware->data))[dsp_code->
                word_count];
-       ps_dsp_code->word_count++;
+       dsp_code->word_count++;
        return 0;
 }
 
 /*-------------------------------------------------------------------*/
 short hpi_dsp_code_read_block(size_t words_requested,
-       struct dsp_code *ps_dsp_code, u32 **ppblock)
+       struct dsp_code *dsp_code, u32 **ppblock)
 {
-       if (ps_dsp_code->word_count + words_requested >
-               ps_dsp_code->block_length)
+       if (dsp_code->word_count + words_requested > dsp_code->block_length)
                return HPI_ERROR_DSP_FILE_FORMAT;
 
        *ppblock =
-               ((u32 *)(ps_dsp_code->ps_firmware->data)) +
-               ps_dsp_code->word_count;
-       ps_dsp_code->word_count += words_requested;
+               ((u32 *)(dsp_code->pvt->firmware->data)) +
+               dsp_code->word_count;
+       dsp_code->word_count += words_requested;
        return 0;
 }
index 65f0ca7..b228811 100644 (file)
@@ -2,7 +2,7 @@
 /**
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
 \file
 Functions for reading DSP code to load into DSP
 
- hpi_dspcode_defines HPI DSP code loading method
-Define exactly one of these to select how the DSP code is supplied to
-the adapter.
-
-End users writing applications that use the HPI interface do not have to
-use any of the below defines; they are only necessary for building drivers
-
-HPI_DSPCODE_FILE:
-DSP code is supplied as a file that is opened and read from by the driver.
-
-HPI_DSPCODE_FIRMWARE:
-DSP code is read using the hotplug firmware loader module.
-     Only valid when compiling the HPI kernel driver under Linux.
 */
 /***********************************************************************/
 #ifndef _HPIDSPCD_H_
@@ -40,37 +27,56 @@ DSP code is read using the hotplug firmware loader module.
 
 #include "hpi_internal.h"
 
-#ifndef DISABLE_PRAGMA_PACK1
-#pragma pack(push, 1)
-#endif
+/** Code header version is decimal encoded e.g. 4.06.10 is 40601 */
+#define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \
+HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
+
+/** Header structure for dsp firmware file
+ This structure must match that used in s2bin.c for generation of asidsp.bin
+ */
+/*#ifndef DISABLE_PRAGMA_PACK1 */
+/*#pragma pack(push, 1) */
+/*#endif */
+struct code_header {
+       /** Size in bytes including header */
+       u32 size;
+       /** File type tag "CODE" == 0x45444F43 */
+       u32 type;
+       /** Adapter model number */
+       u32 adapter;
+       /** Firmware version*/
+       u32 version;
+       /** Data checksum */
+       u32 checksum;
+};
+/*#ifndef DISABLE_PRAGMA_PACK1 */
+/*#pragma pack(pop) */
+/*#endif */
+
+/*? Don't need the pragmas? */
+compile_time_assert((sizeof(struct code_header) == 20), code_header_size);
 
 /** Descriptor for dspcode from firmware loader */
 struct dsp_code {
-       /**  Firmware descriptor */
-       const struct firmware *ps_firmware;
-       struct pci_dev *ps_dev;
+       /** copy of  file header */
+       struct code_header header;
        /** Expected number of words in the whole dsp code,INCL header */
-       long int block_length;
+       u32 block_length;
        /** Number of words read so far */
-       long int word_count;
-       /** Version read from dsp code file */
-       u32 version;
-       /** CRC read from dsp code file */
-       u32 crc;
-};
+       u32 word_count;
 
-#ifndef DISABLE_PRAGMA_PACK1
-#pragma pack(pop)
-#endif
+       /** internal state of DSP code reader */
+       struct dsp_code_private *pvt;
+};
 
-/** Prepare *psDspCode to refer to the requuested adapter.
- Searches the file, or selects the appropriate linked array
+/** Prepare *psDspCode to refer to the requested adapter's firmware.
+Code file name is obtained from HpiOs_GetDspCodePath
 
 \return 0 for success, or error code if requested code is not available
 */
 short hpi_dsp_code_open(
        /** Code identifier, usually adapter family */
-       u32 adapter,
+       u32 adapter, void *pci_dev,
        /** Pointer to DSP code control structure */
        struct dsp_code *ps_dsp_code,
        /** Pointer to dword to receive OS specific error code */
index 7397b16..ebb568d 100644 (file)
@@ -1663,68 +1663,64 @@ u16 hpi_channel_mode_get(u32 h_control, u16 *mode)
 u16 hpi_cobranet_hmi_write(u32 h_control, u32 hmi_address, u32 byte_count,
        u8 *pb_data)
 {
-       struct hpi_message hm;
-       struct hpi_response hr;
+       struct hpi_msg_cobranet_hmiwrite hm;
+       struct hpi_response_header hr;
 
-       hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
-               HPI_CONTROL_SET_STATE);
-       if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
-               return HPI_ERROR_INVALID_HANDLE;
+       hpi_init_message_responseV1(&hm.h, sizeof(hm), &hr, sizeof(hr),
+               HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
 
-       hm.u.cx.u.cobranet_data.byte_count = byte_count;
-       hm.u.cx.u.cobranet_data.hmi_address = hmi_address;
+       if (hpi_handle_indexes(h_control, &hm.h.adapter_index,
+                       &hm.h.obj_index))
+               return HPI_ERROR_INVALID_HANDLE;
 
-       if (byte_count <= 8) {
-               memcpy(hm.u.cx.u.cobranet_data.data, pb_data, byte_count);
-               hm.u.cx.attribute = HPI_COBRANET_SET;
-       } else {
-               hm.u.cx.u.cobranet_bigdata.pb_data = pb_data;
-               hm.u.cx.attribute = HPI_COBRANET_SET_DATA;
-       }
+       if (byte_count > sizeof(hm.bytes))
+               return HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL;
 
-       hpi_send_recv(&hm, &hr);
+       hm.p.attribute = HPI_COBRANET_SET;
+       hm.p.byte_count = byte_count;
+       hm.p.hmi_address = hmi_address;
+       memcpy(hm.bytes, pb_data, byte_count);
+       hm.h.size = (u16)(sizeof(hm.h) + sizeof(hm.p) + byte_count);
 
+       hpi_send_recvV1(&hm.h, &hr);
        return hr.error;
 }
 
 u16 hpi_cobranet_hmi_read(u32 h_control, u32 hmi_address, u32 max_byte_count,
        u32 *pbyte_count, u8 *pb_data)
 {
-       struct hpi_message hm;
-       struct hpi_response hr;
+       struct hpi_msg_cobranet_hmiread hm;
+       struct hpi_res_cobranet_hmiread hr;
 
-       hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
-               HPI_CONTROL_GET_STATE);
-       if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+       hpi_init_message_responseV1(&hm.h, sizeof(hm), &hr.h, sizeof(hr),
+               HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
+
+       if (hpi_handle_indexes(h_control, &hm.h.adapter_index,
+                       &hm.h.obj_index))
                return HPI_ERROR_INVALID_HANDLE;
 
-       hm.u.cx.u.cobranet_data.byte_count = max_byte_count;
-       hm.u.cx.u.cobranet_data.hmi_address = hmi_address;
+       if (max_byte_count > sizeof(hr.bytes))
+               return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
 
-       if (max_byte_count <= 8) {
-               hm.u.cx.attribute = HPI_COBRANET_GET;
-       } else {
-               hm.u.cx.u.cobranet_bigdata.pb_data = pb_data;
-               hm.u.cx.attribute = HPI_COBRANET_GET_DATA;
-       }
+       hm.p.attribute = HPI_COBRANET_GET;
+       hm.p.byte_count = max_byte_count;
+       hm.p.hmi_address = hmi_address;
 
-       hpi_send_recv(&hm, &hr);
-       if (!hr.error && pb_data) {
+       hpi_send_recvV1(&hm.h, &hr.h);
 
-               *pbyte_count = hr.u.cx.u.cobranet_data.byte_count;
+       if (!hr.h.error && pb_data) {
+               if (hr.byte_count > sizeof(hr.bytes))
 
-               if (*pbyte_count < max_byte_count)
-                       max_byte_count = *pbyte_count;
+                       return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
 
-               if (hm.u.cx.attribute == HPI_COBRANET_GET) {
-                       memcpy(pb_data, hr.u.cx.u.cobranet_data.data,
-                               max_byte_count);
-               } else {
+               *pbyte_count = hr.byte_count;
 
-               }
+               if (hr.byte_count < max_byte_count)
+                       max_byte_count = *pbyte_count;
 
+               memcpy(pb_data, hr.bytes, max_byte_count);
        }
-       return hr.error;
+       return hr.h.error;
 }
 
 u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus,
@@ -1733,23 +1729,23 @@ u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus,
        struct hpi_message hm;
        struct hpi_response hr;
 
-       hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
+       hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
                HPI_CONTROL_GET_STATE);
        if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
                return HPI_ERROR_INVALID_HANDLE;
 
-       hm.u.cx.attribute = HPI_COBRANET_GET_STATUS;
+       hm.u.c.attribute = HPI_COBRANET_GET_STATUS;
 
        hpi_send_recv(&hm, &hr);
        if (!hr.error) {
                if (pstatus)
-                       *pstatus = hr.u.cx.u.cobranet_status.status;
+                       *pstatus = hr.u.cu.cobranet.status.status;
                if (preadable_size)
                        *preadable_size =
-                               hr.u.cx.u.cobranet_status.readable_size;
+                               hr.u.cu.cobranet.status.readable_size;
                if (pwriteable_size)
                        *pwriteable_size =
-                               hr.u.cx.u.cobranet_status.writeable_size;
+                               hr.u.cu.cobranet.status.writeable_size;
        }
        return hr.error;
 }
index 628376c..52400a6 100644 (file)
@@ -46,7 +46,7 @@ static void hpi_init_message(struct hpi_message *phm, u16 object,
        if (gwSSX2_bypass)
                phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE;
        else
-               phm->type = HPI_TYPE_MESSAGE;
+               phm->type = HPI_TYPE_REQUEST;
        phm->object = object;
        phm->function = function;
        phm->version = 0;
@@ -89,7 +89,7 @@ static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size,
        memset(phm, 0, sizeof(*phm));
        if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) {
                phm->size = size;
-               phm->type = HPI_TYPE_MESSAGE;
+               phm->type = HPI_TYPE_REQUEST;
                phm->object = object;
                phm->function = function;
                phm->version = 1;
index 7352a5f..2e77942 100644 (file)
@@ -16,7 +16,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-Extended Message Function With Response Cacheing
+Extended Message Function With Response Caching
 
 (C) Copyright AudioScience Inc. 2002
 *****************************************************************************/
@@ -186,7 +186,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
                /* Initialize this module's internal state */
                hpios_msgxlock_init(&msgx_lock);
                memset(&hpi_entry_points, 0, sizeof(hpi_entry_points));
-               hpios_locked_mem_init();
                /* Init subsys_findadapters response to no-adapters */
                HPIMSGX__reset(HPIMSGX_ALLADAPTERS);
                hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
@@ -197,7 +196,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
        case HPI_SUBSYS_DRIVER_UNLOAD:
                HPI_COMMON(phm, phr);
                HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner);
-               hpios_locked_mem_free_all();
                hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
                        HPI_SUBSYS_DRIVER_UNLOAD, 0);
                return;
@@ -315,7 +313,7 @@ void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
 {
        HPI_DEBUG_MESSAGE(DEBUG, phm);
 
-       if (phm->type != HPI_TYPE_MESSAGE) {
+       if (phm->type != HPI_TYPE_REQUEST) {
                hpi_init_response(phr, phm->object, phm->function,
                        HPI_ERROR_INVALID_TYPE);
                return;
index d8e7047..65fcf47 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
@@ -157,11 +157,6 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                goto out;
        }
 
-       if (hm->h.adapter_index >= HPI_MAX_ADAPTERS) {
-               err = -EINVAL;
-               goto out;
-       }
-
        switch (hm->h.function) {
        case HPI_SUBSYS_CREATE_ADAPTER:
        case HPI_ADAPTER_DELETE:
@@ -187,7 +182,6 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                /* -1=no data 0=read from user mem, 1=write to user mem */
                int wrflag = -1;
                u32 adapter = hm->h.adapter_index;
-               pa = &adapters[adapter];
 
                if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) {
                        hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
@@ -203,6 +197,8 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        goto out;
                }
 
+               pa = &adapters[adapter];
+
                if (mutex_lock_interruptible(&adapters[adapter].mutex)) {
                        err = -EINTR;
                        goto out;
index 742ee12..ff2a19b 100644 (file)
@@ -39,10 +39,6 @@ void hpios_delay_micro_seconds(u32 num_micro_sec)
 
 }
 
-void hpios_locked_mem_init(void)
-{
-}
-
 /** Allocated an area of locked memory for bus master DMA operations.
 
 On error, return -ENOMEM, and *pMemArea.size = 0
@@ -85,7 +81,3 @@ u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area)
                return 1;
        }
 }
-
-void hpios_locked_mem_free_all(void)
-{
-}
index 03273e7..2f605e3 100644 (file)
@@ -38,6 +38,7 @@ HPI Operating System Specific macros for Linux Kernel driver
 #include <linux/firmware.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
 
 #define HPI_NO_OS_FILE_OPS
 
index 3119cd9..537e0a2 100644 (file)
@@ -1624,7 +1624,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card,
        }
 
        if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
-                       card->shortname, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_atiixp_free(chip);
                return -EBUSY;
@@ -1701,7 +1701,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "ATI IXP AC97 controller",
+       .name = KBUILD_MODNAME,
        .id_table = snd_atiixp_ids,
        .probe = snd_atiixp_probe,
        .remove = __devexit_p(snd_atiixp_remove),
index 2f74c2f..45df275 100644 (file)
@@ -1260,7 +1260,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card,
        }
 
        if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
-                       card->shortname, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_atiixp_free(chip);
                return -EBUSY;
@@ -1332,7 +1332,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "ATI IXP MC97 controller",
+       .name = KBUILD_MODNAME,
        .id_table = snd_atiixp_ids,
        .probe = snd_atiixp_probe,
        .remove = __devexit_p(snd_atiixp_remove),
index 7b72c88..a384699 100644 (file)
@@ -196,7 +196,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
        }
 
        if ((err = request_irq(pci->irq, vortex_interrupt,
-                              IRQF_SHARED, CARD_NAME_SHORT,
+                              IRQF_SHARED, KBUILD_MODNAME,
                               chip)) != 0) {
                printk(KERN_ERR "cannot grab irq\n");
                goto irq_out;
@@ -375,7 +375,7 @@ static void __devexit snd_vortex_remove(struct pci_dev *pci)
 
 // pci_driver definition
 static struct pci_driver driver = {
-       .name = CARD_NAME_SHORT,
+       .name = KBUILD_MODNAME,
        .id_table = snd_vortex_ids,
        .probe = snd_vortex_probe,
        .remove = __devexit_p(snd_vortex_remove),
index c150022..f8569b1 100644 (file)
@@ -171,7 +171,7 @@ MODULE_DEVICE_TABLE(pci, snd_aw2_ids);
 
 /* pci_driver definition */
 static struct pci_driver driver = {
-       .name = "Emagic Audiowerk 2",
+       .name = KBUILD_MODNAME,
        .id_table = snd_aw2_ids,
        .probe = snd_aw2_probe,
        .remove = __devexit_p(snd_aw2_remove),
@@ -317,7 +317,7 @@ static int __devinit snd_aw2_create(struct snd_card *card,
        snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
 
        if (request_irq(pci->irq, snd_aw2_saa7146_interrupt,
-                       IRQF_SHARED, "Audiowerk2", chip)) {
+                       IRQF_SHARED, KBUILD_MODNAME, chip)) {
                printk(KERN_ERR "aw2: Cannot grab irq %d\n", pci->irq);
 
                iounmap(chip->iobase_virt);
index 9b7a634..e4d76a2 100644 (file)
@@ -2559,7 +2559,7 @@ snd_azf3328_create(struct snd_card *card,
        codec_setup->name = "I2S_OUT";
 
        if (request_irq(pci->irq, snd_azf3328_interrupt,
-                       IRQF_SHARED, card->shortname, chip)) {
+                       IRQF_SHARED, KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                err = -EBUSY;
                goto out_err;
@@ -2860,7 +2860,7 @@ snd_azf3328_resume(struct pci_dev *pci)
 
 
 static struct pci_driver driver = {
-       .name = "AZF3328",
+       .name = KBUILD_MODNAME,
        .id_table = snd_azf3328_ids,
        .probe = snd_azf3328_probe,
        .remove = __devexit_p(snd_azf3328_remove),
index 2958a05..3918033 100644 (file)
@@ -760,7 +760,7 @@ static int __devinit snd_bt87x_create(struct snd_card *card,
        snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS);
 
        err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED,
-                         "Bt87x audio", chip);
+                         KBUILD_MODNAME, chip);
        if (err < 0) {
                snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
                goto fail;
@@ -965,7 +965,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = {
 };
 
 static struct pci_driver driver = {
-       .name = "Bt87x",
+       .name = KBUILD_MODNAME,
        .id_table = snd_bt87x_ids,
        .probe = snd_bt87x_probe,
        .remove = __devexit_p(snd_bt87x_remove),
index 4377592..061b7e6 100644 (file)
@@ -1666,7 +1666,7 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
        }
 
        if (request_irq(pci->irq, snd_ca0106_interrupt,
-                       IRQF_SHARED, "snd_ca0106", chip)) {
+                       IRQF_SHARED, KBUILD_MODNAME, chip)) {
                snd_ca0106_free(chip);
                printk(KERN_ERR "cannot grab irq\n");
                return -EBUSY;
@@ -1933,7 +1933,7 @@ MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);
 
 // pci_driver definition
 static struct pci_driver driver = {
-       .name = "CA0106",
+       .name = KBUILD_MODNAME,
        .id_table = snd_ca0106_ids,
        .probe = snd_ca0106_probe,
        .remove = __devexit_p(snd_ca0106_remove),
index f4e5735..9cf99fb 100644 (file)
@@ -3053,7 +3053,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
        cm->iobase = pci_resource_start(pci, 0);
 
        if (request_irq(pci->irq, snd_cmipci_interrupt,
-                       IRQF_SHARED, card->driver, cm)) {
+                       IRQF_SHARED, KBUILD_MODNAME, cm)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_cmipci_free(cm);
                return -EBUSY;
@@ -3398,7 +3398,7 @@ static int snd_cmipci_resume(struct pci_dev *pci)
 #endif /* CONFIG_PM */
 
 static struct pci_driver driver = {
-       .name = "C-Media PCI",
+       .name = KBUILD_MODNAME,
        .id_table = snd_cmipci_ids,
        .probe = snd_cmipci_probe,
        .remove = __devexit_p(snd_cmipci_remove),
index 6772070..07f04e3 100644 (file)
@@ -1382,7 +1382,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
        }
        
        if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED,
-                       "CS4281", chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_cs4281_free(chip);
                return -ENOMEM;
@@ -2085,7 +2085,7 @@ static int cs4281_resume(struct pci_dev *pci)
 #endif /* CONFIG_PM */
 
 static struct pci_driver driver = {
-       .name = "CS4281",
+       .name = KBUILD_MODNAME,
        .id_table = snd_cs4281_ids,
        .probe = snd_cs4281_probe,
        .remove = __devexit_p(snd_cs4281_remove),
index 767fa7f..1af9555 100644 (file)
@@ -162,7 +162,7 @@ static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "Sound Fusion CS46xx",
+       .name = KBUILD_MODNAME,
        .id_table = snd_cs46xx_ids,
        .probe = snd_card_cs46xx_probe,
        .remove = __devexit_p(snd_card_cs46xx_remove),
index aad3708..9546bf0 100644 (file)
@@ -3835,7 +3835,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
        }
 
        if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_SHARED,
-                       "CS46XX", chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_cs46xx_free(chip);
                return -EBUSY;
index bc07e27..a466934 100644 (file)
@@ -285,7 +285,7 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci,
 }
 
 static struct pci_driver driver = {
-       .name = "CS5530_Audio",
+       .name = KBUILD_MODNAME,
        .id_table = snd_cs5530_ids,
        .probe = snd_cs5530_probe,
        .remove = __devexit_p(snd_cs5530_remove),
index afb8037..10d22ed 100644 (file)
@@ -311,7 +311,7 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card,
        cs5535au->port = pci_resource_start(pci, 0);
 
        if (request_irq(pci->irq, snd_cs5535audio_interrupt,
-                       IRQF_SHARED, "CS5535 Audio", cs5535au)) {
+                       IRQF_SHARED, KBUILD_MODNAME, cs5535au)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                err = -EBUSY;
                goto sndfail;
@@ -395,7 +395,7 @@ static void __devexit snd_cs5535audio_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = DRIVER_NAME,
+       .name = KBUILD_MODNAME,
        .id_table = snd_cs5535audio_ids,
        .probe = snd_cs5535audio_probe,
        .remove = __devexit_p(snd_cs5535audio_remove),
index e0394e3..ca501ba 100644 (file)
@@ -55,6 +55,7 @@
 /* GPIO Registers */
 #define GPIO_DATA           0x1B7020
 #define GPIO_CTRL           0x1B7024
+#define GPIO_EXT_DATA       0x1B70A0
 
 /* Virtual memory registers */
 #define VMEM_PTPAL          0x1C6300 /* 0x1C6300 + (16 * Chn) */
index 13f33c0..d8a4423 100644 (file)
@@ -18,7 +18,6 @@
 #include "ctatc.h"
 #include "ctpcm.h"
 #include "ctmixer.h"
-#include "cthardware.h"
 #include "ctsrc.h"
 #include "ctamixer.h"
 #include "ctdaio.h"
@@ -30,7 +29,6 @@
 #include <sound/asoundef.h>
 
 #define MONO_SUM_SCALE 0x19a8  /* 2^(-0.5) in 14-bit floating format */
-#define DAIONUM                7
 #define MAX_MULTI_CHN  8
 
 #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
@@ -53,6 +51,8 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = {
 static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
                      "SB0760", CTSB0760),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270,
+                     "SB1270", CTSB1270),
        SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
                      "SB0880", CTSB0880),
        SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
@@ -75,6 +75,7 @@ static const char *ct_subsys_name[NUM_CTCARDS] = {
        [CTSB0760]      = "SB076x",
        [CTHENDRIX]     = "Hendrix",
        [CTSB0880]      = "SB0880",
+       [CTSB1270]      = "SB1270",
        [CT20K2_UNKNOWN] = "Unknown",
 };
 
@@ -459,12 +460,12 @@ static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm,
                                apcm->substream->runtime->rate);
        *n_srcc = 0;
 
-       if (1 == atc->msr) {
+       if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */
                *n_srcc = apcm->substream->runtime->channels;
                conf[0].pitch = pitch;
                conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
                conf[0].vo = 1;
-       } else if (2 == atc->msr) {
+       } else if (2 <= atc->msr) {
                if (0x8000000 < pitch) {
                        /* Need two-stage SRCs, SRCIMPs and
                         * AMIXERs for converting format */
@@ -970,11 +971,39 @@ static int atc_select_mic_in(struct ct_atc *atc)
        return 0;
 }
 
-static int atc_have_digit_io_switch(struct ct_atc *atc)
+static struct capabilities atc_capabilities(struct ct_atc *atc)
 {
        struct hw *hw = atc->hw;
 
-       return hw->have_digit_io_switch(hw);
+       return hw->capabilities(hw);
+}
+
+static int atc_output_switch_get(struct ct_atc *atc)
+{
+       struct hw *hw = atc->hw;
+
+       return hw->output_switch_get(hw);
+}
+
+static int atc_output_switch_put(struct ct_atc *atc, int position)
+{
+       struct hw *hw = atc->hw;
+
+       return hw->output_switch_put(hw, position);
+}
+
+static int atc_mic_source_switch_get(struct ct_atc *atc)
+{
+       struct hw *hw = atc->hw;
+
+       return hw->mic_source_switch_get(hw);
+}
+
+static int atc_mic_source_switch_put(struct ct_atc *atc, int position)
+{
+       struct hw *hw = atc->hw;
+
+       return hw->mic_source_switch_put(hw, position);
 }
 
 static int atc_select_digit_io(struct ct_atc *atc)
@@ -1045,6 +1074,11 @@ static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state)
        return atc_daio_unmute(atc, state, LINEIM);
 }
 
+static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
+{
+       return atc_daio_unmute(atc, state, MIC);
+}
+
 static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
 {
        return atc_daio_unmute(atc, state, SPDIFOO);
@@ -1331,17 +1365,20 @@ static int atc_get_resources(struct ct_atc *atc)
        struct srcimp_mgr *srcimp_mgr;
        struct sum_desc sum_dsc = {0};
        struct sum_mgr *sum_mgr;
-       int err, i;
+       int err, i, num_srcs, num_daios;
 
-       atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
+       num_daios = ((atc->model == CTSB1270) ? 8 : 7);
+       num_srcs = ((atc->model == CTSB1270) ? 6 : 4);
+
+       atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL);
        if (!atc->daios)
                return -ENOMEM;
 
-       atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+       atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
        if (!atc->srcs)
                return -ENOMEM;
 
-       atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+       atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
        if (!atc->srcimps)
                return -ENOMEM;
 
@@ -1351,8 +1388,9 @@ static int atc_get_resources(struct ct_atc *atc)
 
        daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
        da_desc.msr = atc->msr;
-       for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) {
-               da_desc.type = i;
+       for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
+               da_desc.type = (atc->model != CTSB073X) ? i :
+                            ((i == SPDIFIO) ? SPDIFI1 : i);
                err = daio_mgr->get_daio(daio_mgr, &da_desc,
                                        (struct daio **)&atc->daios[i]);
                if (err) {
@@ -1362,23 +1400,12 @@ static int atc_get_resources(struct ct_atc *atc)
                }
                atc->n_daio++;
        }
-       if (atc->model == CTSB073X)
-               da_desc.type = SPDIFI1;
-       else
-               da_desc.type = SPDIFIO;
-       err = daio_mgr->get_daio(daio_mgr, &da_desc,
-                               (struct daio **)&atc->daios[i]);
-       if (err) {
-               printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n");
-               return err;
-       }
-       atc->n_daio++;
 
        src_mgr = atc->rsc_mgrs[SRC];
        src_dsc.multi = 1;
        src_dsc.msr = atc->msr;
        src_dsc.mode = ARCRW;
-       for (i = 0, atc->n_src = 0; i < (2*2); i++) {
+       for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
                err = src_mgr->get_src(src_mgr, &src_dsc,
                                        (struct src **)&atc->srcs[i]);
                if (err)
@@ -1388,8 +1415,8 @@ static int atc_get_resources(struct ct_atc *atc)
        }
 
        srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-       srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */
-       for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) {
+       srcimp_dsc.msr = 8;
+       for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
                err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
                                        (struct srcimp **)&atc->srcimps[i]);
                if (err)
@@ -1397,15 +1424,6 @@ static int atc_get_resources(struct ct_atc *atc)
 
                atc->n_srcimp++;
        }
-       srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */
-       for (i = 0; i < (2*1); i++) {
-               err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
-                               (struct srcimp **)&atc->srcimps[2*1+i]);
-               if (err)
-                       return err;
-
-               atc->n_srcimp++;
-       }
 
        sum_mgr = atc->rsc_mgrs[SUM];
        sum_dsc.msr = atc->msr;
@@ -1488,6 +1506,18 @@ static void atc_connect_resources(struct ct_atc *atc)
        src = atc->srcs[3];
        mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
 
+       if (atc->model == CTSB1270) {
+               /* Titanium HD has a dedicated ADC for the Mic. */
+               dai = container_of(atc->daios[MIC], struct dai, daio);
+               atc_connect_dai(atc->rsc_mgrs[SRC], dai,
+                       (struct src **)&atc->srcs[4],
+                       (struct srcimp **)&atc->srcimps[4]);
+               src = atc->srcs[4];
+               mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
+               src = atc->srcs[5];
+               mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
+       }
+
        dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
        atc_connect_dai(atc->rsc_mgrs[SRC], dai,
                        (struct src **)&atc->srcs[0],
@@ -1606,12 +1636,17 @@ static struct ct_atc atc_preset __devinitdata = {
        .line_clfe_unmute = atc_line_clfe_unmute,
        .line_rear_unmute = atc_line_rear_unmute,
        .line_in_unmute = atc_line_in_unmute,
+       .mic_unmute = atc_mic_unmute,
        .spdif_out_unmute = atc_spdif_out_unmute,
        .spdif_in_unmute = atc_spdif_in_unmute,
        .spdif_out_get_status = atc_spdif_out_get_status,
        .spdif_out_set_status = atc_spdif_out_set_status,
        .spdif_out_passthru = atc_spdif_out_passthru,
-       .have_digit_io_switch = atc_have_digit_io_switch,
+       .capabilities = atc_capabilities,
+       .output_switch_get = atc_output_switch_get,
+       .output_switch_put = atc_output_switch_put,
+       .mic_source_switch_get = atc_mic_source_switch_get,
+       .mic_source_switch_put = atc_mic_source_switch_put,
 #ifdef CONFIG_PM
        .suspend = atc_suspend,
        .resume = atc_resume,
index 7167c01..3a0def6 100644 (file)
@@ -25,6 +25,7 @@
 #include <sound/core.h>
 
 #include "ctvmem.h"
+#include "cthardware.h"
 #include "ctresource.h"
 
 enum CTALSADEVS {              /* Types of alsa devices */
@@ -115,12 +116,17 @@ struct ct_atc {
        int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
        int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
        int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
+       int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
        int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
        int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
        int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
        int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
        int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
-       int (*have_digit_io_switch)(struct ct_atc *atc);
+       struct capabilities (*capabilities)(struct ct_atc *atc);
+       int (*output_switch_get)(struct ct_atc *atc);
+       int (*output_switch_put)(struct ct_atc *atc, int position);
+       int (*mic_source_switch_get)(struct ct_atc *atc);
+       int (*mic_source_switch_put)(struct ct_atc *atc, int position);
 
        /* Don't touch! Used for internal object. */
        void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
index 47d9ea9..0c00eb4 100644 (file)
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#define DAIO_RESOURCE_NUM      NUM_DAIOTYP
 #define DAIO_OUT_MAX           SPDIFOO
 
-union daio_usage {
-       struct {
-               unsigned short lineo1:1;
-               unsigned short lineo2:1;
-               unsigned short lineo3:1;
-               unsigned short lineo4:1;
-               unsigned short spdifoo:1;
-               unsigned short lineim:1;
-               unsigned short spdifio:1;
-               unsigned short spdifi1:1;
-       } bf;
+struct daio_usage {
        unsigned short data;
 };
 
@@ -61,6 +50,7 @@ struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
        [LINEO3] = {.left = 0x50, .right = 0x51},
        [LINEO4] = {.left = 0x70, .right = 0x71},
        [LINEIM] = {.left = 0x45, .right = 0xc5},
+       [MIC]    = {.left = 0x55, .right = 0xd5},
        [SPDIFOO] = {.left = 0x00, .right = 0x01},
        [SPDIFIO] = {.left = 0x05, .right = 0x85},
 };
@@ -138,6 +128,7 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
                case LINEO3:    return 5;
                case LINEO4:    return 6;
                case LINEIM:    return 4;
+               case MIC:       return 5;
                default:        return -EINVAL;
                }
        default:
@@ -519,17 +510,17 @@ static int dai_rsc_uninit(struct dai *dai)
 
 static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-       if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
+       if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type))
                return -ENOENT;
 
-       ((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
+       ((struct daio_usage *)mgr->rscs)->data |= (0x1 << type);
 
        return 0;
 }
 
 static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-       ((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
+       ((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
 
        return 0;
 }
@@ -712,7 +703,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
        if (!daio_mgr)
                return -ENOMEM;
 
-       err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
+       err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw);
        if (err)
                goto error1;
 
index 0f52ce5..85ccb6e 100644 (file)
@@ -33,6 +33,7 @@ enum DAIOTYP {
        SPDIFOO,        /* S/PDIF Out (Flexijack/Optical) */
        LINEIM,
        SPDIFIO,        /* S/PDIF In (Flexijack/Optical) on the card */
+       MIC,            /* Dedicated mic on Titanium HD */
        SPDIFI1,        /* S/PDIF In on internal Drive Bay */
        NUM_DAIOTYP
 };
index af55405..908315b 100644 (file)
@@ -39,6 +39,7 @@ enum CTCARDS {
        CT20K2_MODEL_FIRST = CTSB0760,
        CTHENDRIX,
        CTSB0880,
+       CTSB1270,
        CT20K2_UNKNOWN,
        NUM_CTCARDS             /* This should always be the last */
 };
@@ -60,6 +61,13 @@ struct card_conf {
        unsigned int msr;       /* master sample rate in rsrs */
 };
 
+struct capabilities {
+       unsigned int digit_io_switch:1;
+       unsigned int dedicated_mic:1;
+       unsigned int output_switch:1;
+       unsigned int mic_source_switch:1;
+};
+
 struct hw {
        int (*card_init)(struct hw *hw, struct card_conf *info);
        int (*card_stop)(struct hw *hw);
@@ -70,7 +78,11 @@ struct hw {
 #endif
        int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
        int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
-       int (*have_digit_io_switch)(struct hw *hw);
+       struct capabilities (*capabilities)(struct hw *hw);
+       int (*output_switch_get)(struct hw *hw);
+       int (*output_switch_put)(struct hw *hw, int position);
+       int (*mic_source_switch_get)(struct hw *hw);
+       int (*mic_source_switch_put)(struct hw *hw, int position);
 
        /* SRC operations */
        int (*src_rsc_get_ctrl_blk)(void **rblk);
index a5c957d..a7df197 100644 (file)
@@ -1777,10 +1777,17 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
                return adc_init_SBx(hw, info->input, info->mic20db);
 }
 
-static int hw_have_digit_io_switch(struct hw *hw)
+static struct capabilities hw_capabilities(struct hw *hw)
 {
+       struct capabilities cap;
+
        /* SB073x and Vista compatible cards have no digit IO switch */
-       return !(hw->model == CTSB073X || hw->model == CTUAA);
+       cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA);
+       cap.dedicated_mic = 0;
+       cap.output_switch = 0;
+       cap.mic_source_switch = 0;
+
+       return cap;
 }
 
 #define CTLBITS(a, b, c, d)    (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
@@ -1933,7 +1940,7 @@ static int hw_card_start(struct hw *hw)
 
        if (hw->irq < 0) {
                err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
-                                 "ctxfi", hw);
+                                 KBUILD_MODNAME, hw);
                if (err < 0) {
                        printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
                        goto error2;
@@ -2172,7 +2179,7 @@ static struct hw ct20k1_preset __devinitdata = {
        .pll_init = hw_pll_init,
        .is_adc_source_selected = hw_is_adc_input_selected,
        .select_adc_source = hw_adc_input_select,
-       .have_digit_io_switch = hw_have_digit_io_switch,
+       .capabilities = hw_capabilities,
 #ifdef CONFIG_PM
        .suspend = hw_suspend,
        .resume = hw_resume,
index 5364164..d6c54b5 100644 (file)
@@ -8,7 +8,7 @@
  * @File       cthw20k2.c
  *
  * @Brief
- * This file contains the implementation of hardware access methord for 20k2.
+ * This file contains the implementation of hardware access method for 20k2.
  *
  * @Author     Liu Chun
  * @Date       May 14 2008
@@ -38,6 +38,8 @@ struct hw20k2 {
        unsigned char dev_id;
        unsigned char addr_size;
        unsigned char data_size;
+
+       int mic_source;
 };
 
 static u32 hw_read_20kx(struct hw *hw, u32 reg);
@@ -1163,7 +1165,12 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
                hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
                hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
        } else if (2 == info->msr) {
-               hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
+               if (hw->model != CTSB1270) {
+                       hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
+               } else {
+                       /* PCM4220 on Titanium HD is different. */
+                       hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111);
+               }
                /* Specify all playing 96khz
                 * EA [0]       - Enabled
                 * RTA [4:5]    - 96kHz
@@ -1175,6 +1182,10 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
                 * RTD [28:29]  - 96kHz */
                hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
                hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+       } else if ((4 == info->msr) && (hw->model == CTSB1270)) {
+               hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
+               hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
+               hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
        } else {
                printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
                return -EINVAL;
@@ -1182,6 +1193,8 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
 
        for (i = 0; i < 8; i++) {
                if (i <= 3) {
+                       /* This comment looks wrong since loop is over 4  */
+                       /* channels and emu20k2 supports 4 spdif IOs.     */
                        /* 1st 3 channels are SPDIFs (SB0960) */
                        if (i == 3)
                                data = 0x1001001;
@@ -1206,12 +1219,16 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
 
                        hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
                } else {
+                       /* Again, loop is over 4 channels not 5. */
                        /* Next 5 channels are I2S (SB0960) */
                        data = 0x11;
                        hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
                        if (2 == info->msr) {
                                /* Four channels per sample period */
                                data |= 0x1000;
+                       } else if (4 == info->msr) {
+                               /* FIXME: check this against the chip spec */
+                               data |= 0x2000;
                        }
                        hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
                }
@@ -1299,21 +1316,18 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr)
 
        pllenb = 0xB;
        hw_write_20kx(hw, PLL_ENB, pllenb);
-       pllctl = 0x20D00000;
-       set_field(&pllctl, PLLCTL_FD, 16 - 4);
+       pllctl = 0x20C00000;
+       set_field(&pllctl, PLLCTL_B, 0);
+       set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 4 : 147 - 4);
+       set_field(&pllctl, PLLCTL_RD, 48000 == rsr ? 1 - 1 : 10 - 1);
        hw_write_20kx(hw, PLL_CTL, pllctl);
        mdelay(40);
+
        pllctl = hw_read_20kx(hw, PLL_CTL);
-       set_field(&pllctl, PLLCTL_B, 0);
-       if (48000 == rsr) {
-               set_field(&pllctl, PLLCTL_FD, 16 - 2);
-               set_field(&pllctl, PLLCTL_RD, 1 - 1); /* 3000*16/1 = 48000 */
-       } else { /* 44100 */
-               set_field(&pllctl, PLLCTL_FD, 147 - 2);
-               set_field(&pllctl, PLLCTL_RD, 10 - 1); /* 3000*147/10 = 44100 */
-       }
+       set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 2 : 147 - 2);
        hw_write_20kx(hw, PLL_CTL, pllctl);
        mdelay(40);
+
        for (i = 0; i < 1000; i++) {
                pllstat = hw_read_20kx(hw, PLL_STAT);
                if (get_field(pllstat, PLLSTAT_PD))
@@ -1557,7 +1571,7 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
 
        hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
        hw20k2_i2c_wait_data_ready(hw);
-       /* Dummy write to trigger the write oprtation */
+       /* Dummy write to trigger the write operation */
        hw_write_20kx(hw, I2C_IF_WDATA, 0);
        hw20k2_i2c_wait_data_ready(hw);
 
@@ -1568,6 +1582,30 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
        return 0;
 }
 
+static void hw_dac_stop(struct hw *hw)
+{
+       u32 data;
+       data = hw_read_20kx(hw, GPIO_DATA);
+       data &= 0xFFFFFFFD;
+       hw_write_20kx(hw, GPIO_DATA, data);
+       mdelay(10);
+}
+
+static void hw_dac_start(struct hw *hw)
+{
+       u32 data;
+       data = hw_read_20kx(hw, GPIO_DATA);
+       data |= 0x2;
+       hw_write_20kx(hw, GPIO_DATA, data);
+       mdelay(50);
+}
+
+static void hw_dac_reset(struct hw *hw)
+{
+       hw_dac_stop(hw);
+       hw_dac_start(hw);
+}
+
 static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 {
        int err;
@@ -1594,6 +1632,21 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
                                   0x00000000   /* Vol Control B4 */
                                 };
 
+       if (hw->model == CTSB1270) {
+               hw_dac_stop(hw);
+               data = hw_read_20kx(hw, GPIO_DATA);
+               data &= ~0x0600;
+               if (1 == info->msr)
+                       data |= 0x0000; /* Single Speed Mode 0-50kHz */
+               else if (2 == info->msr)
+                       data |= 0x0200; /* Double Speed Mode 50-100kHz */
+               else
+                       data |= 0x0600; /* Quad Speed Mode 100-200kHz */
+               hw_write_20kx(hw, GPIO_DATA, data);
+               hw_dac_start(hw);
+               return 0;
+       }
+
        /* Set DAC reset bit as output */
        data = hw_read_20kx(hw, GPIO_CTRL);
        data |= 0x02;
@@ -1606,22 +1659,8 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
        for (i = 0; i < 2; i++) {
                /* Reset DAC twice just in-case the chip
                 * didn't initialized properly */
-               data = hw_read_20kx(hw, GPIO_DATA);
-               /* GPIO data bit 1 */
-               data &= 0xFFFFFFFD;
-               hw_write_20kx(hw, GPIO_DATA, data);
-               mdelay(10);
-               data |= 0x2;
-               hw_write_20kx(hw, GPIO_DATA, data);
-               mdelay(50);
-
-               /* Reset the 2nd time */
-               data &= 0xFFFFFFFD;
-               hw_write_20kx(hw, GPIO_DATA, data);
-               mdelay(10);
-               data |= 0x2;
-               hw_write_20kx(hw, GPIO_DATA, data);
-               mdelay(50);
+               hw_dac_reset(hw);
+               hw_dac_reset(hw);
 
                if (hw20k2_i2c_read(hw, CS4382_MC1,  &cs_read.mode_control_1))
                        continue;
@@ -1725,7 +1764,11 @@ End:
 static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
 {
        u32 data;
-
+       if (hw->model == CTSB1270) {
+               /* Titanium HD has two ADC chips, one for line in and one */
+               /* for MIC. We don't need to switch the ADC input. */
+               return 1;
+       }
        data = hw_read_20kx(hw, GPIO_DATA);
        switch (type) {
        case ADC_MICIN:
@@ -1742,35 +1785,47 @@ static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
 
 #define MIC_BOOST_0DB 0xCF
 #define MIC_BOOST_STEPS_PER_DB 2
-#define MIC_BOOST_20DB (MIC_BOOST_0DB + 20 * MIC_BOOST_STEPS_PER_DB)
+
+static void hw_wm8775_input_select(struct hw *hw, u8 input, s8 gain_in_db)
+{
+       u32 adcmc, gain;
+
+       if (input > 3)
+               input = 3;
+
+       adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */
+
+       hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc),
+                               MAKE_WM8775_DATA(adcmc));
+
+       if (gain_in_db < -103)
+               gain_in_db = -103;
+       if (gain_in_db > 24)
+               gain_in_db = 24;
+
+       gain = gain_in_db * MIC_BOOST_STEPS_PER_DB + MIC_BOOST_0DB;
+
+       hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain),
+                               MAKE_WM8775_DATA(gain));
+       /* ...so there should be no need for the following. */
+       hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain),
+                               MAKE_WM8775_DATA(gain));
+}
 
 static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
 {
        u32 data;
-
        data = hw_read_20kx(hw, GPIO_DATA);
        switch (type) {
        case ADC_MICIN:
                data |= (0x1 << 14);
                hw_write_20kx(hw, GPIO_DATA, data);
-               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-                               MAKE_WM8775_DATA(0x101)); /* Mic-in */
-               hw20k2_i2c_write(hw,
-                               MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB),
-                               MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
-               hw20k2_i2c_write(hw,
-                               MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB),
-                               MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
+               hw_wm8775_input_select(hw, 0, 20); /* Mic, 20dB */
                break;
        case ADC_LINEIN:
                data &= ~(0x1 << 14);
                hw_write_20kx(hw, GPIO_DATA, data);
-               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-                               MAKE_WM8775_DATA(0x102)); /* Line-in */
-               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-                               MAKE_WM8775_DATA(0xCF)); /* No boost */
-               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-                               MAKE_WM8775_DATA(0xCF)); /* No boost */
+               hw_wm8775_input_select(hw, 1, 0); /* Line-in, 0dB */
                break;
        default:
                break;
@@ -1782,7 +1837,7 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
 static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 {
        int err;
-       u32 mux = 2, data, ctl;
+       u32 data, ctl;
 
        /*  Set ADC reset bit as output */
        data = hw_read_20kx(hw, GPIO_CTRL);
@@ -1796,19 +1851,42 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
                goto error;
        }
 
-       /* Make ADC in normal operation */
+       /* Reset the ADC (reset is active low). */
        data = hw_read_20kx(hw, GPIO_DATA);
        data &= ~(0x1 << 15);
+       hw_write_20kx(hw, GPIO_DATA, data);
+
+       if (hw->model == CTSB1270) {
+               /* Set up the PCM4220 ADC on Titanium HD */
+               data &= ~0x0C;
+               if (1 == info->msr)
+                       data |= 0x00; /* Single Speed Mode 32-50kHz */
+               else if (2 == info->msr)
+                       data |= 0x08; /* Double Speed Mode 50-108kHz */
+               else
+                       data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */
+               hw_write_20kx(hw, GPIO_DATA, data);
+       }
+
        mdelay(10);
+       /* Return the ADC to normal operation. */
        data |= (0x1 << 15);
        hw_write_20kx(hw, GPIO_DATA, data);
        mdelay(50);
 
+       /* I2C write to register offset 0x0B to set ADC LRCLK polarity */
+       /* invert bit, interface format to I2S, word length to 24-bit, */
+       /* enable ADC high pass filter. Fixes bug 5323?         */
+       hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26),
+                        MAKE_WM8775_DATA(0x26));
+
        /* Set the master mode (256fs) */
        if (1 == info->msr) {
+               /* slave mode, 128x oversampling 256fs */
                hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
                                                MAKE_WM8775_DATA(0x02));
-       } else if (2 == info->msr) {
+       } else if ((2 == info->msr) || (4 == info->msr)) {
+               /* slave mode, 64x oversampling, 256fs */
                hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
                                                MAKE_WM8775_DATA(0x0A));
        } else {
@@ -1818,55 +1896,113 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
                goto error;
        }
 
-       /* Configure GPIO bit 14 change to line-in/mic-in */
-       ctl = hw_read_20kx(hw, GPIO_CTRL);
-       ctl |= 0x1 << 14;
-       hw_write_20kx(hw, GPIO_CTRL, ctl);
-
-       /* Check using Mic-in or Line-in */
-       data = hw_read_20kx(hw, GPIO_DATA);
-
-       if (mux == 1) {
-               /* Configures GPIO data to select Mic-in */
-               data |= 0x1 << 14;
-               hw_write_20kx(hw, GPIO_DATA, data);
-
-               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-                               MAKE_WM8775_DATA(0x101)); /* Mic-in */
-               hw20k2_i2c_write(hw,
-                               MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB),
-                               MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
-               hw20k2_i2c_write(hw,
-                               MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB),
-                               MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
-       } else if (mux == 2) {
-               /* Configures GPIO data to select Line-in */
-               data &= ~(0x1 << 14);
-               hw_write_20kx(hw, GPIO_DATA, data);
-
-               /* Setup ADC */
-               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-                               MAKE_WM8775_DATA(0x102)); /* Line-in */
-               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-                               MAKE_WM8775_DATA(0xCF)); /* No boost */
-               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-                               MAKE_WM8775_DATA(0xCF)); /* No boost */
+       if (hw->model != CTSB1270) {
+               /* Configure GPIO bit 14 change to line-in/mic-in */
+               ctl = hw_read_20kx(hw, GPIO_CTRL);
+               ctl |= 0x1 << 14;
+               hw_write_20kx(hw, GPIO_CTRL, ctl);
+               hw_adc_input_select(hw, ADC_LINEIN);
        } else {
-               printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n");
-               err = -EINVAL;
-               goto error;
+               hw_wm8775_input_select(hw, 0, 0);
        }
 
        return 0;
-
 error:
        hw20k2_i2c_uninit(hw);
        return err;
 }
 
-static int hw_have_digit_io_switch(struct hw *hw)
+static struct capabilities hw_capabilities(struct hw *hw)
 {
-       return 0;
+       struct capabilities cap;
+
+       cap.digit_io_switch = 0;
+       cap.dedicated_mic = hw->model == CTSB1270;
+       cap.output_switch = hw->model == CTSB1270;
+       cap.mic_source_switch = hw->model == CTSB1270;
+
+       return cap;
+}
+
+static int hw_output_switch_get(struct hw *hw)
+{
+       u32 data = hw_read_20kx(hw, GPIO_EXT_DATA);
+
+       switch (data & 0x30) {
+       case 0x00:
+            return 0;
+       case 0x10:
+            return 1;
+       case 0x20:
+            return 2;
+       default:
+            return 3;
+       }
+}
+
+static int hw_output_switch_put(struct hw *hw, int position)
+{
+       u32 data;
+
+       if (position == hw_output_switch_get(hw))
+               return 0;
+
+       /* Mute line and headphones (intended for anti-pop). */
+       data = hw_read_20kx(hw, GPIO_DATA);
+       data |= (0x03 << 11);
+       hw_write_20kx(hw, GPIO_DATA, data);
+
+       data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30;
+       switch (position) {
+       case 0:
+               break;
+       case 1:
+               data |= 0x10;
+               break;
+       default:
+               data |= 0x20;
+       }
+       hw_write_20kx(hw, GPIO_EXT_DATA, data);
+
+       /* Unmute line and headphones. */
+       data = hw_read_20kx(hw, GPIO_DATA);
+       data &= ~(0x03 << 11);
+       hw_write_20kx(hw, GPIO_DATA, data);
+
+       return 1;
+}
+
+static int hw_mic_source_switch_get(struct hw *hw)
+{
+       struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+       return hw20k2->mic_source;
+}
+
+static int hw_mic_source_switch_put(struct hw *hw, int position)
+{
+       struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+       if (position == hw20k2->mic_source)
+               return 0;
+
+       switch (position) {
+       case 0:
+               hw_wm8775_input_select(hw, 0, 0); /* Mic, 0dB */
+               break;
+       case 1:
+               hw_wm8775_input_select(hw, 1, 0); /* FP Mic, 0dB */
+               break;
+       case 2:
+               hw_wm8775_input_select(hw, 3, 0); /* Aux Ext, 0dB */
+               break;
+       default:
+               return 0;
+       }
+
+       hw20k2->mic_source = position;
+
+       return 1;
 }
 
 static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
@@ -1925,7 +2061,7 @@ static int hw_card_start(struct hw *hw)
 
        if (hw->irq < 0) {
                err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED,
-                                 "ctxfi", hw);
+                                 KBUILD_MODNAME, hw);
                if (err < 0) {
                        printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
                        goto error2;
@@ -2023,13 +2159,16 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
        /* Reset all SRC pending interrupts */
        hw_write_20kx(hw, SRC_IP, 0);
 
-       /* TODO: detect the card ID and configure GPIO accordingly. */
-       /* Configures GPIO (0xD802 0x98028) */
-       /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
-       /* Configures GPIO (SB0880) */
-       /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
-       hw_write_20kx(hw, GPIO_CTRL, 0xD802);
-
+       if (hw->model != CTSB1270) {
+               /* TODO: detect the card ID and configure GPIO accordingly. */
+               /* Configures GPIO (0xD802 0x98028) */
+               /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
+               /* Configures GPIO (SB0880) */
+               /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
+               hw_write_20kx(hw, GPIO_CTRL, 0xD802);
+       } else {
+               hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
+       }
        /* Enable audio ring */
        hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
 
@@ -2106,7 +2245,11 @@ static struct hw ct20k2_preset __devinitdata = {
        .pll_init = hw_pll_init,
        .is_adc_source_selected = hw_is_adc_input_selected,
        .select_adc_source = hw_adc_input_select,
-       .have_digit_io_switch = hw_have_digit_io_switch,
+       .capabilities = hw_capabilities,
+       .output_switch_get = hw_output_switch_get,
+       .output_switch_put = hw_output_switch_put,
+       .mic_source_switch_get = hw_mic_source_switch_get,
+       .mic_source_switch_put = hw_mic_source_switch_put,
 #ifdef CONFIG_PM
        .suspend = hw_suspend,
        .resume = hw_resume,
index c3519ff..0cc13ee 100644 (file)
@@ -86,9 +86,7 @@ enum CTALSA_MIXER_CTL {
        MIXER_LINEIN_C_S,
        MIXER_MIC_C_S,
        MIXER_SPDIFI_C_S,
-       MIXER_LINEIN_P_S,
        MIXER_SPDIFO_P_S,
-       MIXER_SPDIFI_P_S,
        MIXER_WAVEF_P_S,
        MIXER_WAVER_P_S,
        MIXER_WAVEC_P_S,
@@ -137,11 +135,11 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
        },
        [MIXER_LINEIN_P] = {
                .ctl = 1,
-               .name = "Line-in Playback Volume",
+               .name = "Line Playback Volume",
        },
        [MIXER_LINEIN_C] = {
                .ctl = 1,
-               .name = "Line-in Capture Volume",
+               .name = "Line Capture Volume",
        },
        [MIXER_MIC_P] = {
                .ctl = 1,
@@ -153,15 +151,15 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
        },
        [MIXER_SPDIFI_P] = {
                .ctl = 1,
-               .name = "S/PDIF-in Playback Volume",
+               .name = "IEC958 Playback Volume",
        },
        [MIXER_SPDIFI_C] = {
                .ctl = 1,
-               .name = "S/PDIF-in Capture Volume",
+               .name = "IEC958 Capture Volume",
        },
        [MIXER_SPDIFO_P] = {
                .ctl = 1,
-               .name = "S/PDIF-out Playback Volume",
+               .name = "Digital Playback Volume",
        },
        [MIXER_WAVEF_P] = {
                .ctl = 1,
@@ -179,14 +177,13 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
                .ctl = 1,
                .name = "Surround Playback Volume",
        },
-
        [MIXER_PCM_C_S] = {
                .ctl = 1,
                .name = "PCM Capture Switch",
        },
        [MIXER_LINEIN_C_S] = {
                .ctl = 1,
-               .name = "Line-in Capture Switch",
+               .name = "Line Capture Switch",
        },
        [MIXER_MIC_C_S] = {
                .ctl = 1,
@@ -194,19 +191,11 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
        },
        [MIXER_SPDIFI_C_S] = {
                .ctl = 1,
-               .name = "S/PDIF-in Capture Switch",
-       },
-       [MIXER_LINEIN_P_S] = {
-               .ctl = 1,
-               .name = "Line-in Playback Switch",
+               .name = "IEC958 Capture Switch",
        },
        [MIXER_SPDIFO_P_S] = {
                .ctl = 1,
-               .name = "S/PDIF-out Playback Switch",
-       },
-       [MIXER_SPDIFI_P_S] = {
-               .ctl = 1,
-               .name = "S/PDIF-in Playback Switch",
+               .name = "Digital Playback Switch",
        },
        [MIXER_WAVEF_P_S] = {
                .ctl = 1,
@@ -236,6 +225,8 @@ ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
 static void
 ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
 
+/* FIXME: this static looks like it would fail if more than one card was */
+/* installed. */
 static struct snd_kcontrol *kctls[2] = {NULL};
 
 static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
@@ -420,6 +411,77 @@ static struct snd_kcontrol_new vol_ctl = {
        .tlv            = { .p =  ct_vol_db_scale },
 };
 
+static int output_switch_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+         "FP Headphones", "Headphones", "Speakers"
+       };
+
+       return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int output_switch_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc);
+       return 0;
+}
+
+static int output_switch_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+       if (ucontrol->value.enumerated.item[0] > 2)
+               return -EINVAL;
+       return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]);
+}
+
+static struct snd_kcontrol_new output_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Analog Output Playback Enum",
+       .info = output_switch_info,
+       .get = output_switch_get,
+       .put = output_switch_put,
+};
+
+static int mic_source_switch_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+         "Mic", "FP Mic", "Aux"
+       };
+
+       return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int mic_source_switch_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc);
+       return 0;
+}
+
+static int mic_source_switch_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+       if (ucontrol->value.enumerated.item[0] > 2)
+               return -EINVAL;
+       return atc->mic_source_switch_put(atc,
+                                       ucontrol->value.enumerated.item[0]);
+}
+
+static struct snd_kcontrol_new mic_source_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Mic Source Capture Enum",
+       .info = mic_source_switch_info,
+       .get = mic_source_switch_get,
+       .put = mic_source_switch_put,
+};
+
 static void
 do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
 {
@@ -465,6 +527,7 @@ do_digit_io_switch(struct ct_atc *atc, int state)
 static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
 {
        struct ct_mixer *mixer = atc->mixer;
+       struct capabilities cap = atc->capabilities(atc);
 
        /* Do changes in mixer. */
        if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
@@ -477,8 +540,17 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
                }
        }
        /* Do changes out of mixer. */
-       if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
-               do_line_mic_switch(atc, type);
+       if (!cap.dedicated_mic &&
+           (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) {
+               if (state)
+                       do_line_mic_switch(atc, type);
+               atc->line_in_unmute(atc, state);
+       } else if (cap.dedicated_mic && (MIXER_LINEIN_C_S == type))
+               atc->line_in_unmute(atc, state);
+       else if (cap.dedicated_mic && (MIXER_MIC_C_S == type))
+               atc->mic_unmute(atc, state);
+       else if (MIXER_SPDIFI_C_S == type)
+               atc->spdif_in_unmute(atc, state);
        else if (MIXER_WAVEF_P_S == type)
                atc->line_front_unmute(atc, state);
        else if (MIXER_WAVES_P_S == type)
@@ -487,12 +559,8 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
                atc->line_clfe_unmute(atc, state);
        else if (MIXER_WAVER_P_S == type)
                atc->line_rear_unmute(atc, state);
-       else if (MIXER_LINEIN_P_S == type)
-               atc->line_in_unmute(atc, state);
        else if (MIXER_SPDIFO_P_S == type)
                atc->spdif_out_unmute(atc, state);
-       else if (MIXER_SPDIFI_P_S == type)
-               atc->spdif_in_unmute(atc, state);
        else if (MIXER_DIGITAL_IO_S == type)
                do_digit_io_switch(atc, state);
 
@@ -671,6 +739,7 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 {
        enum CTALSA_MIXER_CTL type;
        struct ct_atc *atc = mixer->atc;
+       struct capabilities cap = atc->capabilities(atc);
        int err;
 
        /* Create snd kcontrol instances on demand */
@@ -684,8 +753,8 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
                }
        }
 
-       ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
-                                       atc->have_digit_io_switch(atc);
+       ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = cap.digit_io_switch;
+
        for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
                if (ct_kcontrol_init_table[type].ctl) {
                        swh_ctl.name = ct_kcontrol_init_table[type].name;
@@ -708,6 +777,17 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
        if (err)
                return err;
 
+       if (cap.output_switch) {
+               err = ct_mixer_kcontrol_new(mixer, &output_ctl);
+               if (err)
+                       return err;
+       }
+
+       if (cap.mic_source_switch) {
+               err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl);
+               if (err)
+                       return err;
+       }
        atc->line_front_unmute(atc, 1);
        set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
        atc->line_surround_unmute(atc, 0);
@@ -719,13 +799,12 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
        atc->spdif_out_unmute(atc, 0);
        set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
        atc->line_in_unmute(atc, 0);
-       set_switch_state(mixer, MIXER_LINEIN_P_S, 0);
+       if (cap.dedicated_mic)
+               atc->mic_unmute(atc, 0);
        atc->spdif_in_unmute(atc, 0);
-       set_switch_state(mixer, MIXER_SPDIFI_P_S, 0);
-
-       set_switch_state(mixer, MIXER_PCM_C_S, 1);
-       set_switch_state(mixer, MIXER_LINEIN_C_S, 1);
-       set_switch_state(mixer, MIXER_SPDIFI_C_S, 1);
+       set_switch_state(mixer, MIXER_PCM_C_S, 0);
+       set_switch_state(mixer, MIXER_LINEIN_C_S, 0);
+       set_switch_state(mixer, MIXER_SPDIFI_C_S, 0);
 
        return 0;
 }
index f42e7e1..b259aa0 100644 (file)
@@ -80,11 +80,11 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                       "are 48000 and 44100, Value 48000 is assumed.\n");
                reference_rate = 48000;
        }
-       if ((multiple != 1) && (multiple != 2)) {
+       if ((multiple != 1) && (multiple != 2) && (multiple != 4)) {
                printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
                       multiple);
                printk(KERN_ERR "ctxfi: The valid values for multiple are "
-                      "1 and 2, Value 2 is assumed.\n");
+                      "1, 2 and 4, Value 2 is assumed.\n");
                multiple = 2;
        }
        err = ct_atc_create(card, pci, reference_rate, multiple,
@@ -143,7 +143,7 @@ static int ct_card_resume(struct pci_dev *pci)
 #endif
 
 static struct pci_driver ct_driver = {
-       .name = "SB-XFi",
+       .name = KBUILD_MODNAME,
        .id_table = ct_pci_dev_ids,
        .probe = ct_card_probe,
        .remove = __devexit_p(ct_card_remove),
index 20763dd..d730698 100644 (file)
@@ -1995,7 +1995,7 @@ static __devinit int snd_echo_create(struct snd_card *card,
                ioremap_nocache(chip->dsp_registers_phys, sz);
 
        if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
-                       ECHOCARD_NAME, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_echo_free(chip);
                snd_printk(KERN_ERR "cannot grab irq\n");
                return -EBUSY;
@@ -2286,7 +2286,7 @@ static int snd_echo_resume(struct pci_dev *pci)
        kfree(commpage_bak);
 
        if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
-                       ECHOCARD_NAME, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_echo_free(chip);
                snd_printk(KERN_ERR "cannot grab irq\n");
                return -EBUSY;
@@ -2327,7 +2327,7 @@ static void __devexit snd_echo_remove(struct pci_dev *pci)
 
 /* pci_driver definition */
 static struct pci_driver driver = {
-       .name = "Echoaudio " ECHOCARD_NAME,
+       .name = KBUILD_MODNAME,
        .id_table = snd_echo_ids,
        .probe = snd_echo_probe,
        .remove = __devexit_p(snd_echo_remove),
index aff8387..a9c45d2 100644 (file)
@@ -264,7 +264,7 @@ static int snd_emu10k1_resume(struct pci_dev *pci)
 #endif
 
 static struct pci_driver driver = {
-       .name = "EMU10K1_Audigy",
+       .name = KBUILD_MODNAME,
        .id_table = snd_emu10k1_ids,
        .probe = snd_card_emu10k1_probe,
        .remove = __devexit_p(snd_card_emu10k1_remove),
index 15f0161..fcd4935 100644 (file)
@@ -1912,7 +1912,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
 
        /* irq handler must be registered after I/O ports are activated */
        if (request_irq(pci->irq, snd_emu10k1_interrupt, IRQF_SHARED,
-                       "EMU10K1", emu)) {
+                       KBUILD_MODNAME, emu)) {
                err = -EBUSY;
                goto error;
        }
index 0c701e4..d4fde1b 100644 (file)
@@ -925,7 +925,7 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card,
        }
 
        if (request_irq(pci->irq, snd_emu10k1x_interrupt,
-                       IRQF_SHARED, "EMU10K1X", chip)) {
+                       IRQF_SHARED, KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq);
                snd_emu10k1x_free(chip);
                return -EBUSY;
@@ -1613,7 +1613,7 @@ MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
 
 // pci_driver definition
 static struct pci_driver driver = {
-       .name = "EMU10K1X",
+       .name = KBUILD_MODNAME,
        .id_table = snd_emu10k1x_ids,
        .probe = snd_emu10k1x_probe,
        .remove = __devexit_p(snd_emu10k1x_remove),
index 863eafe..f02e2f8 100644 (file)
@@ -2120,7 +2120,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
        }
        ensoniq->port = pci_resource_start(pci, 0);
        if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_SHARED,
-                       "Ensoniq AudioPCI", ensoniq)) {
+                       KBUILD_MODNAME, ensoniq)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_ensoniq_free(ensoniq);
                return -EBUSY;
@@ -2489,7 +2489,7 @@ static void __devexit snd_audiopci_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = DRIVER_NAME,
+       .name = KBUILD_MODNAME,
        .id_table = snd_audiopci_ids,
        .probe = snd_audiopci_probe,
        .remove = __devexit_p(snd_audiopci_remove),
index 553b752..26a5a2f 100644 (file)
@@ -1514,7 +1514,7 @@ static int es1938_resume(struct pci_dev *pci)
        }
 
        if (request_irq(pci->irq, snd_es1938_interrupt,
-                       IRQF_SHARED, "ES1938", chip)) {
+                       IRQF_SHARED, KBUILD_MODNAME, chip)) {
                printk(KERN_ERR "es1938: unable to grab IRQ %d, "
                       "disabling device\n", pci->irq);
                snd_card_disconnect(card);
@@ -1636,7 +1636,7 @@ static int __devinit snd_es1938_create(struct snd_card *card,
        chip->mpu_port = pci_resource_start(pci, 3);
        chip->game_port = pci_resource_start(pci, 4);
        if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED,
-                       "ES1938", chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_es1938_free(chip);
                return -EBUSY;
@@ -1882,7 +1882,7 @@ static void __devexit snd_es1938_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "ESS ES1938 (Solo-1)",
+       .name = KBUILD_MODNAME,
        .id_table = snd_es1938_ids,
        .probe = snd_es1938_probe,
        .remove = __devexit_p(snd_es1938_remove),
index ab0a615..99ea932 100644 (file)
@@ -554,9 +554,8 @@ struct es1968 {
 #else
        struct snd_kcontrol *master_switch; /* for h/w volume control */
        struct snd_kcontrol *master_volume;
-       spinlock_t ac97_lock;
-       struct tasklet_struct hwvol_tq;
 #endif
+       struct work_struct hwvol_work;
 
 #ifdef CONFIG_SND_ES1968_RADIO
        struct snd_tea575x tea;
@@ -646,38 +645,23 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip)
 static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
 {
        struct es1968 *chip = ac97->private_data;
-#ifndef CONFIG_SND_ES1968_INPUT
-       unsigned long flags;
-#endif
 
        snd_es1968_ac97_wait(chip);
 
        /* Write the bus */
-#ifndef CONFIG_SND_ES1968_INPUT
-       spin_lock_irqsave(&chip->ac97_lock, flags);
-#endif
        outw(val, chip->io_port + ESM_AC97_DATA);
        /*msleep(1);*/
        outb(reg, chip->io_port + ESM_AC97_INDEX);
        /*msleep(1);*/
-#ifndef CONFIG_SND_ES1968_INPUT
-       spin_unlock_irqrestore(&chip->ac97_lock, flags);
-#endif
 }
 
 static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
        u16 data = 0;
        struct es1968 *chip = ac97->private_data;
-#ifndef CONFIG_SND_ES1968_INPUT
-       unsigned long flags;
-#endif
 
        snd_es1968_ac97_wait(chip);
 
-#ifndef CONFIG_SND_ES1968_INPUT
-       spin_lock_irqsave(&chip->ac97_lock, flags);
-#endif
        outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX);
        /*msleep(1);*/
 
@@ -685,9 +669,6 @@ static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short
                data = inw(chip->io_port + ESM_AC97_DATA);
                /*msleep(1);*/
        }
-#ifndef CONFIG_SND_ES1968_INPUT
-       spin_unlock_irqrestore(&chip->ac97_lock, flags);
-#endif
 
        return data;
 }
@@ -1904,13 +1885,10 @@ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es)
    (without wrap around) in response to volume button presses and then
    generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
    of a byte wide register. The meaning of bits 0 and 4 is unknown. */
-static void es1968_update_hw_volume(unsigned long private_data)
+static void es1968_update_hw_volume(struct work_struct *work)
 {
-       struct es1968 *chip = (struct es1968 *) private_data;
+       struct es1968 *chip = container_of(work, struct es1968, hwvol_work);
        int x, val;
-#ifndef CONFIG_SND_ES1968_INPUT
-       unsigned long flags;
-#endif
 
        /* Figure out which volume control button was pushed,
           based on differences from the default register
@@ -1929,18 +1907,11 @@ static void es1968_update_hw_volume(unsigned long private_data)
        if (! chip->master_switch || ! chip->master_volume)
                return;
 
-       /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
-       spin_lock_irqsave(&chip->ac97_lock, flags);
-       val = chip->ac97->regs[AC97_MASTER];
+       val = snd_ac97_read(chip->ac97, AC97_MASTER);
        switch (x) {
        case 0x88:
                /* mute */
                val ^= 0x8000;
-               chip->ac97->regs[AC97_MASTER] = val;
-               outw(val, chip->io_port + ESM_AC97_DATA);
-               outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
-               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                              &chip->master_switch->id);
                break;
        case 0xaa:
                /* volume up */
@@ -1948,11 +1919,6 @@ static void es1968_update_hw_volume(unsigned long private_data)
                        val--;
                if ((val & 0x7f00) > 0)
                        val -= 0x0100;
-               chip->ac97->regs[AC97_MASTER] = val;
-               outw(val, chip->io_port + ESM_AC97_DATA);
-               outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
-               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                              &chip->master_volume->id);
                break;
        case 0x66:
                /* volume down */
@@ -1960,14 +1926,11 @@ static void es1968_update_hw_volume(unsigned long private_data)
                        val++;
                if ((val & 0x7f00) < 0x1f00)
                        val += 0x0100;
-               chip->ac97->regs[AC97_MASTER] = val;
-               outw(val, chip->io_port + ESM_AC97_DATA);
-               outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
-               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                              &chip->master_volume->id);
                break;
        }
-       spin_unlock_irqrestore(&chip->ac97_lock, flags);
+       if (snd_ac97_update(chip->ac97, AC97_MASTER, val))
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &chip->master_volume->id);
 #else
        if (!chip->input_dev)
                return;
@@ -2013,11 +1976,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id)
        outw(inw(chip->io_port + 4) & 1, chip->io_port + 4);
 
        if (event & ESM_HWVOL_IRQ)
-#ifdef CONFIG_SND_ES1968_INPUT
-               es1968_update_hw_volume((unsigned long)chip);
-#else
-               tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */
-#endif
+               schedule_work(&chip->hwvol_work);
 
        /* else ack 'em all, i imagine */
        outb(0xFF, chip->io_port + 0x1A);
@@ -2426,6 +2385,7 @@ static int es1968_suspend(struct pci_dev *pci, pm_message_t state)
                return 0;
 
        chip->in_suspend = 1;
+       cancel_work_sync(&chip->hwvol_work);
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        snd_pcm_suspend_all(chip->pcm);
        snd_ac97_suspend(chip->ac97);
@@ -2638,6 +2598,7 @@ static struct snd_tea575x_ops snd_es1968_tea_ops = {
 
 static int snd_es1968_free(struct es1968 *chip)
 {
+       cancel_work_sync(&chip->hwvol_work);
 #ifdef CONFIG_SND_ES1968_INPUT
        if (chip->input_dev)
                input_unregister_device(chip->input_dev);
@@ -2728,10 +2689,7 @@ static int __devinit snd_es1968_create(struct snd_card *card,
        INIT_LIST_HEAD(&chip->buf_list);
        INIT_LIST_HEAD(&chip->substream_list);
        mutex_init(&chip->memory_mutex);
-#ifndef CONFIG_SND_ES1968_INPUT
-       spin_lock_init(&chip->ac97_lock);
-       tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip);
-#endif
+       INIT_WORK(&chip->hwvol_work, es1968_update_hw_volume);
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
@@ -2746,7 +2704,7 @@ static int __devinit snd_es1968_create(struct snd_card *card,
        }
        chip->io_port = pci_resource_start(pci, 0);
        if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED,
-                       "ESS Maestro", chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_es1968_free(chip);
                return -EBUSY;
@@ -2925,7 +2883,7 @@ static void __devexit snd_es1968_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "ES1968 (ESS Maestro)",
+       .name = KBUILD_MODNAME,
        .id_table = snd_es1968_ids,
        .probe = snd_es1968_probe,
        .remove = __devexit_p(snd_es1968_remove),
index a7ec703..f9123f0 100644 (file)
@@ -1199,7 +1199,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
        chip->port = pci_resource_start(pci, 0);
        if ((tea575x_tuner & TUNER_ONLY) == 0) {
                if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
-                               "FM801", chip)) {
+                               KBUILD_MODNAME, chip)) {
                        snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
                        snd_fm801_free(chip);
                        return -EBUSY;
@@ -1394,7 +1394,7 @@ static int snd_fm801_resume(struct pci_dev *pci)
 #endif
 
 static struct pci_driver driver = {
-       .name = "FM801",
+       .name = KBUILD_MODNAME,
        .id_table = snd_fm801_ids,
        .probe = snd_card_fm801_probe,
        .remove = __devexit_p(snd_card_fm801_remove),
index 0ea5cc6..7489b46 100644 (file)
@@ -14,6 +14,19 @@ menuconfig SND_HDA_INTEL
 
 if SND_HDA_INTEL
 
+config SND_HDA_PREALLOC_SIZE
+       int "Pre-allocated buffer size for HD-audio driver"
+       range 0 32768
+       default 64
+       help
+         Specifies the default pre-allocated buffer-size in kB for the
+         HD-audio driver.  A larger buffer (e.g. 2048) is preferred
+         for systems using PulseAudio.  The default 64 is chosen just
+         for compatibility reasons.
+
+         Note that the pre-allocation size can be changed dynamically
+         via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
+
 config SND_HDA_HWDEP
        bool "Build hwdep interface for HD-audio driver"
        select SND_HWDEP
@@ -83,6 +96,19 @@ config SND_HDA_CODEC_REALTEK
          snd-hda-codec-realtek.
          This module is automatically loaded at probing.
 
+config SND_HDA_ENABLE_REALTEK_QUIRKS
+       bool "Build static quirks for Realtek codecs"
+       depends on SND_HDA_CODEC_REALTEK
+       default y
+       help
+         Say Y here to build the static quirks codes for Realtek codecs.
+         If you need the "model" preset that the default BIOS auto-parser
+         can't handle, turn this option on.
+
+         If your device works with model=auto option, basically you don't
+         need the quirk code.  By turning this off, you can reduce the
+         module size quite a lot.
+
 config SND_HDA_CODEC_ANALOG
        bool "Build Analog Device HD-audio codec support"
        default y
@@ -171,6 +197,19 @@ config SND_HDA_CODEC_CA0110
          snd-hda-codec-ca0110.
          This module is automatically loaded at probing.
 
+config SND_HDA_CODEC_CA0132
+       bool "Build Creative CA0132 codec support"
+       depends on SND_HDA_INTEL
+       default y
+       help
+         Say Y here to include Creative CA0132 codec support in
+         snd-hda-intel driver.
+
+         When the HD-audio driver is built as a module, the codec
+         support code is also built as another module,
+         snd-hda-codec-ca0132.
+         This module is automatically loaded at probing.
+
 config SND_HDA_CODEC_CMEDIA
        bool "Build C-Media HD-audio codec support"
        default y
index 17ef365..87365d5 100644 (file)
@@ -13,6 +13,7 @@ snd-hda-codec-idt-objs :=     patch_sigmatel.o
 snd-hda-codec-si3054-objs :=   patch_si3054.o
 snd-hda-codec-cirrus-objs :=   patch_cirrus.o
 snd-hda-codec-ca0110-objs :=   patch_ca0110.o
+snd-hda-codec-ca0132-objs :=   patch_ca0132.o
 snd-hda-codec-conexant-objs := patch_conexant.o
 snd-hda-codec-via-objs :=      patch_via.o
 snd-hda-codec-hdmi-objs :=     patch_hdmi.o hda_eld.o
@@ -42,6 +43,9 @@ endif
 ifdef CONFIG_SND_HDA_CODEC_CA0110
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
 endif
+ifdef CONFIG_SND_HDA_CODEC_CA0132
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0132.o
+endif
 ifdef CONFIG_SND_HDA_CODEC_CONEXANT
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
 endif
diff --git a/sound/pci/hda/alc260_quirks.c b/sound/pci/hda/alc260_quirks.c
new file mode 100644 (file)
index 0000000..21ec2cb
--- /dev/null
@@ -0,0 +1,1272 @@
+/*
+ * ALC260 quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC260 models */
+enum {
+       ALC260_AUTO,
+       ALC260_BASIC,
+       ALC260_HP,
+       ALC260_HP_DC7600,
+       ALC260_HP_3013,
+       ALC260_FUJITSU_S702X,
+       ALC260_ACER,
+       ALC260_WILL,
+       ALC260_REPLACER_672V,
+       ALC260_FAVORIT100,
+#ifdef CONFIG_SND_DEBUG
+       ALC260_TEST,
+#endif
+       ALC260_MODEL_LAST /* last tag */
+};
+
+static const hda_nid_t alc260_dac_nids[1] = {
+       /* front */
+       0x02,
+};
+
+static const hda_nid_t alc260_adc_nids[1] = {
+       /* ADC0 */
+       0x04,
+};
+
+static const hda_nid_t alc260_adc_nids_alt[1] = {
+       /* ADC1 */
+       0x05,
+};
+
+/* NIDs used when simultaneous access to both ADCs makes sense.  Note that
+ * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
+ */
+static const hda_nid_t alc260_dual_adc_nids[2] = {
+       /* ADC0, ADC1 */
+       0x04, 0x05
+};
+
+#define ALC260_DIGOUT_NID      0x03
+#define ALC260_DIGIN_NID       0x06
+
+static const struct hda_input_mux alc260_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
+/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
+ * headphone jack and the internal CD lines since these are the only pins at
+ * which audio can appear.  For flexibility, also allow the option of
+ * recording the mixer output on the second ADC (ADC0 doesn't have a
+ * connection to the mixer output).
+ */
+static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
+       {
+               .num_items = 3,
+               .items = {
+                       { "Mic/Line", 0x0 },
+                       { "CD", 0x4 },
+                       { "Headphone", 0x2 },
+               },
+       },
+       {
+               .num_items = 4,
+               .items = {
+                       { "Mic/Line", 0x0 },
+                       { "CD", 0x4 },
+                       { "Headphone", 0x2 },
+                       { "Mixer", 0x5 },
+               },
+       },
+
+};
+
+/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
+ * the Fujitsu S702x, but jacks are marked differently.
+ */
+static const struct hda_input_mux alc260_acer_capture_sources[2] = {
+       {
+               .num_items = 4,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+                       { "Headphone", 0x5 },
+               },
+       },
+       {
+               .num_items = 5,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+                       { "Headphone", 0x6 },
+                       { "Mixer", 0x5 },
+               },
+       },
+};
+
+/* Maxdata Favorit 100XS */
+static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
+       {
+               .num_items = 2,
+               .items = {
+                       { "Line/Mic", 0x0 },
+                       { "CD", 0x4 },
+               },
+       },
+       {
+               .num_items = 3,
+               .items = {
+                       { "Line/Mic", 0x0 },
+                       { "CD", 0x4 },
+                       { "Mixer", 0x5 },
+               },
+       },
+};
+
+/*
+ * This is just place-holder, so there's something for alc_build_pcms to look
+ * at when it calculates the maximum number of channels. ALC260 has no mixer
+ * element which allows changing the channel mode, so the verb list is
+ * never used.
+ */
+static const struct hda_channel_mode alc260_modes[1] = {
+       { 2, NULL },
+};
+
+
+/* Mixer combinations
+ *
+ * basic: base_output + input + pc_beep + capture
+ * HP: base_output + input + capture_alt
+ * HP_3013: hp_3013 + input + capture
+ * fujitsu: fujitsu + capture
+ * acer: acer + capture
+ */
+
+static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc260_input_mixer[] = {
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
+       { } /* end */
+};
+
+/* update HP, line and mono out pins according to the master switch */
+static void alc260_hp_master_update(struct hda_codec *codec)
+{
+       update_speakers(codec);
+}
+
+static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       *ucontrol->value.integer.value = !spec->master_mute;
+       return 0;
+}
+
+static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       int val = !*ucontrol->value.integer.value;
+
+       if (val == spec->master_mute)
+               return 0;
+       spec->master_mute = val;
+       alc260_hp_master_update(codec);
+       return 1;
+}
+
+static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc260_hp_master_sw_get,
+               .put = alc260_hp_master_sw_put,
+       },
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
+                             HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_verb alc260_hp_unsol_verbs[] = {
+       {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {},
+};
+
+static void alc260_hp_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x0f;
+       spec->autocfg.speaker_pins[0] = 0x10;
+       spec->autocfg.speaker_pins[1] = 0x11;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc260_hp_master_sw_get,
+               .put = alc260_hp_master_sw_put,
+       },
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static void alc260_hp_3013_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x10;
+       spec->autocfg.speaker_pins[1] = 0x11;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
+       HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {},
+};
+
+static void alc260_hp_3012_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x10;
+       spec->autocfg.speaker_pins[0] = 0x0f;
+       spec->autocfg.speaker_pins[1] = 0x11;
+       spec->autocfg.speaker_pins[2] = 0x15;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+/* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12,
+ * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
+ */
+static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
+       ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
+       ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
+       { } /* end */
+};
+
+/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks.  Note that current
+ * versions of the ALC260 don't act on requests to enable mic bias from NID
+ * 0x0f (used to drive the headphone jack in these laptops).  The ALC260
+ * datasheet doesn't mention this restriction.  At this stage it's not clear
+ * whether this behaviour is intentional or is a hardware bug in chip
+ * revisions available in early 2006.  Therefore for now allow the
+ * "Headphone Jack Mode" control to span all choices, but if it turns out
+ * that the lack of mic bias for this NID is intentional we could change the
+ * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ *
+ * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
+ * don't appear to make the mic bias available from the "line" jack, even
+ * though the NID used for this jack (0x14) can supply it.  The theory is
+ * that perhaps Acer have included blocking capacitors between the ALC260
+ * and the output jack.  If this turns out to be the case for all such
+ * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
+ * to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ *
+ * The C20x Tablet series have a mono internal speaker which is controlled
+ * via the chip's Mono sum widget and pin complex, so include the necessary
+ * controls for such models.  On models without a "mono speaker" the control
+ * won't do anything.
+ */
+static const struct snd_kcontrol_new alc260_acer_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
+       ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
+                             HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
+                          HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+       ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
+       ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
+       { } /* end */
+};
+
+/* Maxdata Favorit 100XS: one output and one input (0x12) jack
+ */
+static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
+       ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
+       HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+       ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
+       { } /* end */
+};
+
+/* Packard bell V7900  ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
+ * Line In jack = 0x14, CD audio =  0x16, pc beep = 0x17.
+ */
+static const struct snd_kcontrol_new alc260_will_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+       ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
+       ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+       { } /* end */
+};
+
+/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
+ * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
+ */
+static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+       ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
+       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
+       ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
+       { } /* end */
+};
+
+/*
+ * initialization verbs
+ */
+static const struct hda_verb alc260_init_verbs[] = {
+       /* Line In pin widget for input */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       /* CD pin widget for input */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       /* Mic1 (rear panel) pin widget for input and vref at 80% */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       /* Mic2 (front panel) pin widget for input and vref at 80% */
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       /* LINE-2 is used for line-out in rear */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       /* select line-out */
+       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* LINE-OUT pin */
+       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       /* enable HP */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* enable Mono */
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       /* mute capture amp left and right */
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* set connection select to line in (default select for this ADC) */
+       {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* mute capture amp left and right */
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* set connection select to line in (default select for this ADC) */
+       {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* set vol=0 Line-Out mixer amp left and right */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* unmute pin widget amp left and right (no gain on this amp) */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* set vol=0 HP mixer amp left and right */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* unmute pin widget amp left and right (no gain on this amp) */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* set vol=0 Mono mixer amp left and right */
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* unmute pin widget amp left and right (no gain on this amp) */
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* unmute LINE-2 out pin */
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
+        * Line In 2 = 0x03
+        */
+       /* mute analog inputs */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
+       /* mute Front out path */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* mute Headphone out path */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* mute Mono out path */
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       { }
+};
+
+#if 0 /* should be identical with alc260_init_verbs? */
+static const struct hda_verb alc260_hp_init_verbs[] = {
+       /* Headphone and output */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       /* mono output */
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* Mic1 (rear panel) pin widget for input and vref at 80% */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       /* Mic2 (front panel) pin widget for input and vref at 80% */
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       /* Line In pin widget for input */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       /* Line-2 pin widget for output */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* CD pin widget for input */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       /* unmute amp left and right */
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+       /* set connection select to line in (default select for this ADC) */
+       {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* unmute Line-Out mixer amp left and right (volume = 0) */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+       /* mute pin widget amp left and right (no gain on this amp) */
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+       /* unmute HP mixer amp left and right (volume = 0) */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+       /* mute pin widget amp left and right (no gain on this amp) */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+       /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
+        * Line In 2 = 0x03
+        */
+       /* mute analog inputs */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
+       /* Unmute Front out path */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       /* Unmute Headphone out path */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       /* Unmute Mono out path */
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       { }
+};
+#endif
+
+static const struct hda_verb alc260_hp_3013_init_verbs[] = {
+       /* Line out and output */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* mono output */
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* Mic1 (rear panel) pin widget for input and vref at 80% */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       /* Mic2 (front panel) pin widget for input and vref at 80% */
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       /* Line In pin widget for input */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       /* Headphone pin widget for output */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       /* CD pin widget for input */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       /* unmute amp left and right */
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+       /* set connection select to line in (default select for this ADC) */
+       {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* unmute Line-Out mixer amp left and right (volume = 0) */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+       /* mute pin widget amp left and right (no gain on this amp) */
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+       /* unmute HP mixer amp left and right (volume = 0) */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+       /* mute pin widget amp left and right (no gain on this amp) */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+       /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
+        * Line In 2 = 0x03
+        */
+       /* mute analog inputs */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
+       /* Unmute Front out path */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       /* Unmute Headphone out path */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       /* Unmute Mono out path */
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       { }
+};
+
+/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
+ * laptops.  ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
+ * audio = 0x16, internal speaker = 0x10.
+ */
+static const struct hda_verb alc260_fujitsu_init_verbs[] = {
+       /* Disable all GPIOs */
+       {0x01, AC_VERB_SET_GPIO_MASK, 0},
+       /* Internal speaker is connected to headphone pin */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Headphone/Line-out jack connects to Line1 pin; make it an output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       /* Ensure all other unused pins are disabled and muted. */
+       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+       /* Disable digital (SPDIF) pins */
+       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
+       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+       /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
+        * when acting as an output.
+        */
+       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* Start with output sum widgets muted and their output gains at min */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Unmute Line1 pin widget output buffer since it starts as an output.
+        * If the pin mode is changed by the user the pin mode control will
+        * take care of enabling the pin's input/output buffers as needed.
+        * Therefore there's no need to enable the input buffer at this
+        * stage.
+        */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Unmute input buffer of pin widget used for Line-in (no equiv
+        * mixer ctrl)
+        */
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Mute capture amp left and right */
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Set ADC connection select to match default mixer setting - line
+        * in (on mic1 pin)
+        */
+       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Do the same for the second ADC: mute capture input amp and
+        * set ADC connection to line in (on mic1 pin)
+        */
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Mute all inputs to mixer widget (even unconnected ones) */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+       { }
+};
+
+/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
+ * similar laptops (adapted from Fujitsu init verbs).
+ */
+static const struct hda_verb alc260_acer_init_verbs[] = {
+       /* On TravelMate laptops, GPIO 0 enables the internal speaker and
+        * the headphone jack.  Turn this on and rely on the standard mute
+        * methods whenever the user wants to turn these outputs off.
+        */
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+       /* Internal speaker/Headphone jack is connected to Line-out pin */
+       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Internal microphone/Mic jack is connected to Mic1 pin */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
+       /* Line In jack is connected to Line1 pin */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Ensure all other unused pins are disabled and muted. */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Disable digital (SPDIF) pins */
+       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
+       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+       /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
+        * bus when acting as outputs.
+        */
+       {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* Start with output sum widgets muted and their output gains at min */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* Unmute Line-out pin widget amp left and right
+        * (no equiv mixer ctrl)
+        */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Unmute Mic1 and Line1 pin widget input buffers since they start as
+        * inputs. If the pin mode is changed by the user the pin mode control
+        * will take care of enabling the pin's input/output buffers as needed.
+        * Therefore there's no need to enable the input buffer at this
+        * stage.
+        */
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Mute capture amp left and right */
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Set ADC connection select to match default mixer setting - mic
+        * (on mic1 pin)
+        */
+       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Do similar with the second ADC: mute capture input amp and
+        * set ADC connection to mic to match ALSA's default state.
+        */
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Mute all inputs to mixer widget (even unconnected ones) */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+       { }
+};
+
+/* Initialisation sequence for Maxdata Favorit 100XS
+ * (adapted from Acer init verbs).
+ */
+static const struct hda_verb alc260_favorit100_init_verbs[] = {
+       /* GPIO 0 enables the output jack.
+        * Turn this on and rely on the standard mute
+        * methods whenever the user wants to turn these outputs off.
+        */
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+       /* Line/Mic input jack is connected to Mic1 pin */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
+       /* Ensure all other unused pins are disabled and muted. */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Disable digital (SPDIF) pins */
+       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
+       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+       /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
+        * bus when acting as outputs.
+        */
+       {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* Start with output sum widgets muted and their output gains at min */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* Unmute Line-out pin widget amp left and right
+        * (no equiv mixer ctrl)
+        */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Unmute Mic1 and Line1 pin widget input buffers since they start as
+        * inputs. If the pin mode is changed by the user the pin mode control
+        * will take care of enabling the pin's input/output buffers as needed.
+        * Therefore there's no need to enable the input buffer at this
+        * stage.
+        */
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Mute capture amp left and right */
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Set ADC connection select to match default mixer setting - mic
+        * (on mic1 pin)
+        */
+       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Do similar with the second ADC: mute capture input amp and
+        * set ADC connection to mic to match ALSA's default state.
+        */
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Mute all inputs to mixer widget (even unconnected ones) */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+       { }
+};
+
+static const struct hda_verb alc260_will_verbs[] = {
+       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+       {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
+       {}
+};
+
+static const struct hda_verb alc260_replacer_672v_verbs[] = {
+       {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+       {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
+
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+
+       {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc260_replacer_672v_automute(struct hda_codec *codec)
+{
+        unsigned int present;
+
+       /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
+       present = snd_hda_jack_detect(codec, 0x0f);
+       if (present) {
+               snd_hda_codec_write_cache(codec, 0x01, 0,
+                                         AC_VERB_SET_GPIO_DATA, 1);
+               snd_hda_codec_write_cache(codec, 0x0f, 0,
+                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                         PIN_HP);
+       } else {
+               snd_hda_codec_write_cache(codec, 0x01, 0,
+                                         AC_VERB_SET_GPIO_DATA, 0);
+               snd_hda_codec_write_cache(codec, 0x0f, 0,
+                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                         PIN_OUT);
+       }
+}
+
+static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
+                                       unsigned int res)
+{
+        if ((res >> 26) == ALC_HP_EVENT)
+                alc260_replacer_672v_automute(codec);
+}
+
+static const struct hda_verb alc260_hp_dc7600_verbs[] = {
+       {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+/* Test configuration for debugging, modelled after the ALC880 test
+ * configuration.
+ */
+#ifdef CONFIG_SND_DEBUG
+static const hda_nid_t alc260_test_dac_nids[1] = {
+       0x02,
+};
+static const hda_nid_t alc260_test_adc_nids[2] = {
+       0x04, 0x05,
+};
+/* For testing the ALC260, each input MUX needs its own definition since
+ * the signal assignments are different.  This assumes that the first ADC
+ * is NID 0x04.
+ */
+static const struct hda_input_mux alc260_test_capture_sources[2] = {
+       {
+               .num_items = 7,
+               .items = {
+                       { "MIC1 pin", 0x0 },
+                       { "MIC2 pin", 0x1 },
+                       { "LINE1 pin", 0x2 },
+                       { "LINE2 pin", 0x3 },
+                       { "CD pin", 0x4 },
+                       { "LINE-OUT pin", 0x5 },
+                       { "HP-OUT pin", 0x6 },
+               },
+        },
+       {
+               .num_items = 8,
+               .items = {
+                       { "MIC1 pin", 0x0 },
+                       { "MIC2 pin", 0x1 },
+                       { "LINE1 pin", 0x2 },
+                       { "LINE2 pin", 0x3 },
+                       { "CD pin", 0x4 },
+                       { "Mixer", 0x5 },
+                       { "LINE-OUT pin", 0x6 },
+                       { "HP-OUT pin", 0x7 },
+               },
+        },
+};
+static const struct snd_kcontrol_new alc260_test_mixer[] = {
+       /* Output driver widgets */
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
+
+       /* Modes for retasking pin widgets
+        * Note: the ALC260 doesn't seem to act on requests to enable mic
+         * bias from NIDs 0x0f and 0x10.  The ALC260 datasheet doesn't
+         * mention this restriction.  At this stage it's not clear whether
+         * this behaviour is intentional or is a hardware bug in chip
+         * revisions available at least up until early 2006.  Therefore for
+         * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
+         * choices, but if it turns out that the lack of mic bias for these
+         * NIDs is intentional we could change their modes from
+         * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
+        */
+       ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
+
+       /* Loopback mixer controls */
+       HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
+       HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
+       HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
+
+       /* Controls for GPIO pins, assuming they are configured as outputs */
+       ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+
+       /* Switches to allow the digital IO pins to be enabled.  The datasheet
+        * is ambigious as to which NID is which; testing on laptops which
+        * make this output available should provide clarification.
+        */
+       ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
+       ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
+
+       /* A switch allowing EAPD to be enabled.  Some laptops seem to use
+        * this output to turn on an external amplifier.
+        */
+       ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
+       ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
+
+       { } /* end */
+};
+static const struct hda_verb alc260_test_init_verbs[] = {
+       /* Enable all GPIOs as outputs with an initial value of 0 */
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
+
+       /* Enable retasking pins as output, initially without power amp */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       /* Disable digital (SPDIF) pins initially, but users can enable
+        * them via a mixer switch.  In the case of SPDIF-out, this initverb
+        * payload also sets the generation to 0, output to be in "consumer"
+        * PCM format, copyright asserted, no pre-emphasis and no validity
+        * control.
+        */
+       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
+       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+       /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
+        * OUT1 sum bus when acting as an output.
+        */
+       {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* Start with output sum widgets muted and their output gains at min */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* Unmute retasking pin widget output buffers since the default
+        * state appears to be output.  As the pin mode is changed by the
+        * user the pin mode control will take care of enabling the pin's
+        * input/output buffers as needed.
+        */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Also unmute the mono-out pin widget */
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Mute capture amp left and right */
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Set ADC connection select to match default mixer setting (mic1
+        * pin)
+        */
+       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Do the same for the second ADC: mute capture input amp and
+        * set ADC connection to mic1 pin
+        */
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Mute all inputs to mixer widget (even unconnected ones) */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+       { }
+};
+#endif
+
+/*
+ * ALC260 configurations
+ */
+static const char * const alc260_models[ALC260_MODEL_LAST] = {
+       [ALC260_BASIC]          = "basic",
+       [ALC260_HP]             = "hp",
+       [ALC260_HP_3013]        = "hp-3013",
+       [ALC260_HP_DC7600]      = "hp-dc7600",
+       [ALC260_FUJITSU_S702X]  = "fujitsu",
+       [ALC260_ACER]           = "acer",
+       [ALC260_WILL]           = "will",
+       [ALC260_REPLACER_672V]  = "replacer",
+       [ALC260_FAVORIT100]     = "favorit100",
+#ifdef CONFIG_SND_DEBUG
+       [ALC260_TEST]           = "test",
+#endif
+       [ALC260_AUTO]           = "auto",
+};
+
+static const struct snd_pci_quirk alc260_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
+       SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
+       SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
+       SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
+       SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
+       SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
+       SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
+       SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
+       SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
+       SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
+       SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
+       SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
+       SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
+       SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
+       SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
+       SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
+       SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
+       SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
+       SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
+       SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
+       {}
+};
+
+static const struct alc_config_preset alc260_presets[] = {
+       [ALC260_BASIC] = {
+               .mixers = { alc260_base_output_mixer,
+                           alc260_input_mixer },
+               .init_verbs = { alc260_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
+               .adc_nids = alc260_dual_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .input_mux = &alc260_capture_source,
+       },
+       [ALC260_HP] = {
+               .mixers = { alc260_hp_output_mixer,
+                           alc260_input_mixer },
+               .init_verbs = { alc260_init_verbs,
+                               alc260_hp_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
+               .adc_nids = alc260_adc_nids_alt,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .input_mux = &alc260_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc260_hp_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC260_HP_DC7600] = {
+               .mixers = { alc260_hp_dc7600_mixer,
+                           alc260_input_mixer },
+               .init_verbs = { alc260_init_verbs,
+                               alc260_hp_dc7600_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
+               .adc_nids = alc260_adc_nids_alt,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .input_mux = &alc260_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc260_hp_3012_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC260_HP_3013] = {
+               .mixers = { alc260_hp_3013_mixer,
+                           alc260_input_mixer },
+               .init_verbs = { alc260_hp_3013_init_verbs,
+                               alc260_hp_3013_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
+               .adc_nids = alc260_adc_nids_alt,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .input_mux = &alc260_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc260_hp_3013_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC260_FUJITSU_S702X] = {
+               .mixers = { alc260_fujitsu_mixer },
+               .init_verbs = { alc260_fujitsu_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
+               .adc_nids = alc260_dual_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
+               .input_mux = alc260_fujitsu_capture_sources,
+       },
+       [ALC260_ACER] = {
+               .mixers = { alc260_acer_mixer },
+               .init_verbs = { alc260_acer_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
+               .adc_nids = alc260_dual_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
+               .input_mux = alc260_acer_capture_sources,
+       },
+       [ALC260_FAVORIT100] = {
+               .mixers = { alc260_favorit100_mixer },
+               .init_verbs = { alc260_favorit100_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
+               .adc_nids = alc260_dual_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
+               .input_mux = alc260_favorit100_capture_sources,
+       },
+       [ALC260_WILL] = {
+               .mixers = { alc260_will_mixer },
+               .init_verbs = { alc260_init_verbs, alc260_will_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
+               .adc_nids = alc260_adc_nids,
+               .dig_out_nid = ALC260_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .input_mux = &alc260_capture_source,
+       },
+       [ALC260_REPLACER_672V] = {
+               .mixers = { alc260_replacer_672v_mixer },
+               .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
+               .adc_nids = alc260_adc_nids,
+               .dig_out_nid = ALC260_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .input_mux = &alc260_capture_source,
+               .unsol_event = alc260_replacer_672v_unsol_event,
+               .init_hook = alc260_replacer_672v_automute,
+       },
+#ifdef CONFIG_SND_DEBUG
+       [ALC260_TEST] = {
+               .mixers = { alc260_test_mixer },
+               .init_verbs = { alc260_test_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
+               .dac_nids = alc260_test_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
+               .adc_nids = alc260_test_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
+               .input_mux = alc260_test_capture_sources,
+       },
+#endif
+};
+
diff --git a/sound/pci/hda/alc262_quirks.c b/sound/pci/hda/alc262_quirks.c
new file mode 100644 (file)
index 0000000..8d2097d
--- /dev/null
@@ -0,0 +1,1353 @@
+/*
+ * ALC262 quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC262 models */
+enum {
+       ALC262_AUTO,
+       ALC262_BASIC,
+       ALC262_HIPPO,
+       ALC262_HIPPO_1,
+       ALC262_FUJITSU,
+       ALC262_HP_BPC,
+       ALC262_HP_BPC_D7000_WL,
+       ALC262_HP_BPC_D7000_WF,
+       ALC262_HP_TC_T5735,
+       ALC262_HP_RP5700,
+       ALC262_BENQ_ED8,
+       ALC262_SONY_ASSAMD,
+       ALC262_BENQ_T31,
+       ALC262_ULTRA,
+       ALC262_LENOVO_3000,
+       ALC262_NEC,
+       ALC262_TOSHIBA_S06,
+       ALC262_TOSHIBA_RX1,
+       ALC262_TYAN,
+       ALC262_MODEL_LAST /* last tag */
+};
+
+#define ALC262_DIGOUT_NID      ALC880_DIGOUT_NID
+#define ALC262_DIGIN_NID       ALC880_DIGIN_NID
+
+#define alc262_dac_nids                alc260_dac_nids
+#define alc262_adc_nids                alc882_adc_nids
+#define alc262_adc_nids_alt    alc882_adc_nids_alt
+#define alc262_capsrc_nids     alc882_capsrc_nids
+#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
+
+#define alc262_modes           alc260_modes
+#define alc262_capture_source  alc882_capture_source
+
+static const hda_nid_t alc262_dmic_adc_nids[1] = {
+       /* ADC0 */
+       0x09
+};
+
+static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
+
+static const struct snd_kcontrol_new alc262_base_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+/* update HP, line and mono-out pins according to the master switch */
+#define alc262_hp_master_update                alc260_hp_master_update
+
+static void alc262_hp_bpc_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x16;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+static void alc262_hp_wildwest_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x16;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+#define alc262_hp_master_sw_get                alc260_hp_master_sw_get
+#define alc262_hp_master_sw_put                alc260_hp_master_sw_put
+
+#define ALC262_HP_MASTER_SWITCH                                        \
+       {                                                       \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
+               .name = "Master Playback Switch",               \
+               .info = snd_ctl_boolean_mono_info,              \
+               .get = alc262_hp_master_sw_get,                 \
+               .put = alc262_hp_master_sw_put,                 \
+       }, \
+       {                                                       \
+               .iface = NID_MAPPING,                           \
+               .name = "Master Playback Switch",               \
+               .private_value = 0x15 | (0x16 << 8) | (0x1b << 16),     \
+       }
+
+
+static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
+       ALC262_HP_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
+                             HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
+                           HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
+       ALC262_HP_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
+                             HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
+                           HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
+       HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       { } /* end */
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_hp_t5735_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_verb alc262_hp_t5735_verbs[] = {
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
+static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_verb alc262_hp_rp5700_verbs[] = {
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
+       {}
+};
+
+static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
+       .num_items = 1,
+       .items = {
+               { "Line", 0x1 },
+       },
+};
+
+/* bind hp and internal speaker mute (with plug check) as master switch */
+#define alc262_hippo_master_update     alc262_hp_master_update
+#define alc262_hippo_master_sw_get     alc262_hp_master_sw_get
+#define alc262_hippo_master_sw_put     alc262_hp_master_sw_put
+
+#define ALC262_HIPPO_MASTER_SWITCH                             \
+       {                                                       \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
+               .name = "Master Playback Switch",               \
+               .info = snd_ctl_boolean_mono_info,              \
+               .get = alc262_hippo_master_sw_get,              \
+               .put = alc262_hippo_master_sw_put,              \
+       },                                                      \
+       {                                                       \
+               .iface = NID_MAPPING,                           \
+               .name = "Master Playback Switch",               \
+               .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
+                            (SUBDEV_SPEAKER(0) << 16), \
+       }
+
+static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_hippo_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc262_hippo1_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+
+static const struct snd_kcontrol_new alc262_sony_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_verb alc262_tyan_verbs[] = {
+       /* Headphone automute */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* P11 AUX_IN, white 4-pin connector */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
+       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
+       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
+
+       {}
+};
+
+/* unsolicited event for HP jack sensing */
+static void alc262_tyan_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+
+#define alc262_capture_mixer           alc882_capture_mixer
+#define alc262_capture_alt_mixer       alc882_capture_alt_mixer
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static const struct hda_verb alc262_init_verbs[] = {
+       /*
+        * Unmute ADC0-2 and set the default input to mic-in
+        */
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        * Note: PASD motherboards uses the Line In 2 as the input for
+        * front panel mic (mic 2)
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /*
+        * Set up output mixers (0x0c - 0x0e)
+        */
+       /* set vol=0 to output mixers */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+
+       { }
+};
+
+static const struct hda_verb alc262_eapd_verbs[] = {
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {}
+};
+
+static const struct hda_verb alc262_sony_unsol_verbs[] = {
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},   // Front Mic
+
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {}
+};
+
+static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_verb alc262_toshiba_s06_verbs[] = {
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static void alc262_toshiba_s06_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x12;
+       spec->auto_mic = 1;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+/*
+ * nec model
+ *  0x15 = headphone
+ *  0x16 = internal speaker
+ *  0x18 = external mic
+ */
+
+static const struct snd_kcontrol_new alc262_nec_mixer[] = {
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static const struct hda_verb alc262_nec_verbs[] = {
+       /* Unmute Speaker */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Headphone */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       /* External mic to headphone */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* External mic to speaker */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {}
+};
+
+/*
+ * fujitsu model
+ *  0x14 = headphone/spdif-out, 0x15 = internal speaker,
+ *  0x1b = port replicator headphone out
+ */
+
+static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {}
+};
+
+static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {}
+};
+
+static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
+       /* Front Mic pin: input vref at 50% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {}
+};
+
+static const struct hda_input_mux alc262_fujitsu_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+               { "CD", 0x4 },
+       },
+};
+
+static const struct hda_input_mux alc262_HP_capture_source = {
+       .num_items = 5,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+               { "AUX IN", 0x6 },
+       },
+};
+
+static const struct hda_input_mux alc262_HP_D7000_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x2 },
+               { "Line", 0x1 },
+               { "CD", 0x4 },
+       },
+};
+
+static void alc262_fujitsu_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.hp_pins[1] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+/* bind volumes of both NID 0x0c and 0x0d */
+static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc262_hp_master_sw_get,
+               .put = alc262_hp_master_sw_put,
+       },
+       {
+               .iface = NID_MAPPING,
+               .name = "Master Playback Switch",
+               .private_value = 0x1b,
+       },
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static void alc262_lenovo_3000_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc262_hp_master_sw_get,
+               .put = alc262_hp_master_sw_put,
+       },
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+/* additional init verbs for Benq laptops */
+static const struct hda_verb alc262_EAPD_verbs[] = {
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x3070},
+       {}
+};
+
+static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x3050},
+       {}
+};
+
+/* Samsung Q1 Ultra Vista model setup */
+static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_verb alc262_ultra_verbs[] = {
+       /* output mixer */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* speaker */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       /* internal mic */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* ADC, choose mic */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
+       {}
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_ultra_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int mute;
+
+       mute = 0;
+       /* auto-mute only when HP is used as HP */
+       if (!spec->cur_mux[0]) {
+               spec->jack_present = snd_hda_jack_detect(codec, 0x15);
+               if (spec->jack_present)
+                       mute = HDA_AMP_MUTE;
+       }
+       /* mute/unmute internal speaker */
+       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, mute);
+       /* mute/unmute HP */
+       snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_ultra_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       if ((res >> 26) != ALC_HP_EVENT)
+               return;
+       alc262_ultra_automute(codec);
+}
+
+static const struct hda_input_mux alc262_ultra_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x1 },
+               { "Headphone", 0x7 },
+       },
+};
+
+static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       int ret;
+
+       ret = alc_mux_enum_put(kcontrol, ucontrol);
+       if (!ret)
+               return 0;
+       /* reprogram the HP pin as mic or HP according to the input source */
+       snd_hda_codec_write_cache(codec, 0x15, 0,
+                                 AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
+       alc262_ultra_automute(codec); /* mute/unmute HP */
+       return ret;
+}
+
+static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Capture Source",
+               .info = alc_mux_enum_info,
+               .get = alc_mux_enum_get,
+               .put = alc262_ultra_mux_enum_put,
+       },
+       {
+               .iface = NID_MAPPING,
+               .name = "Capture Source",
+               .private_value = 0x15,
+       },
+       { } /* end */
+};
+
+static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
+       /*
+        * Unmute ADC0-2 and set the default input to mic-in
+        */
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        * Note: PASD motherboards uses the Line In 2 as the input for
+        * front panel mic (mic 2)
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+
+       /*
+        * Set up output mixers (0x0c - 0x0e)
+        */
+       /* set vol=0 to output mixers */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
+       /* Input mixer1: only unmute Mic */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
+
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+
+       { }
+};
+
+static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
+       /*
+        * Unmute ADC0-2 and set the default input to mic-in
+        */
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        * Note: PASD motherboards uses the Line In 2 as the input for front
+        * panel mic (mic 2)
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+       /*
+        * Set up output mixers (0x0c - 0x0e)
+        */
+       /* set vol=0 to output mixers */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },        /* HP */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },       /* Mono */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* rear MIC */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },        /* Line in */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* Front MIC */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },       /* Line out */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },        /* CD in */
+
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+       /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
+        /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))},  */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+        /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+        /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
+
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+
+       { }
+};
+
+static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },       /* Front Speaker */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* MIC jack */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* Front MIC */
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
+
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },        /* HP  jack */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+/*
+ * configuration and preset
+ */
+static const char * const alc262_models[ALC262_MODEL_LAST] = {
+       [ALC262_BASIC]          = "basic",
+       [ALC262_HIPPO]          = "hippo",
+       [ALC262_HIPPO_1]        = "hippo_1",
+       [ALC262_FUJITSU]        = "fujitsu",
+       [ALC262_HP_BPC]         = "hp-bpc",
+       [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
+       [ALC262_HP_TC_T5735]    = "hp-tc-t5735",
+       [ALC262_HP_RP5700]      = "hp-rp5700",
+       [ALC262_BENQ_ED8]       = "benq",
+       [ALC262_BENQ_T31]       = "benq-t31",
+       [ALC262_SONY_ASSAMD]    = "sony-assamd",
+       [ALC262_TOSHIBA_S06]    = "toshiba-s06",
+       [ALC262_TOSHIBA_RX1]    = "toshiba-rx1",
+       [ALC262_ULTRA]          = "ultra",
+       [ALC262_LENOVO_3000]    = "lenovo-3000",
+       [ALC262_NEC]            = "nec",
+       [ALC262_TYAN]           = "tyan",
+       [ALC262_AUTO]           = "auto",
+};
+
+static const struct snd_pci_quirk alc262_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
+       SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
+                          ALC262_HP_BPC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
+                          ALC262_HP_BPC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
+                          ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200",
+                          ALC262_AUTO),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
+                          ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
+       SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
+       SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
+       SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
+       SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
+       SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
+       SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
+       SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
+       SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
+                     ALC262_HP_TC_T5735),
+       SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
+       SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
+       SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
+       SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
+       SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
+       SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
+       SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
+       SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
+#if 0 /* disable the quirk since model=auto works better in recent versions */
+       SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
+                          ALC262_SONY_ASSAMD),
+#endif
+       SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
+                     ALC262_TOSHIBA_RX1),
+       SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
+       SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
+       SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
+       SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
+       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
+                          ALC262_ULTRA),
+       SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
+       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
+       SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
+       SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
+       SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
+       {}
+};
+
+static const struct alc_config_preset alc262_presets[] = {
+       [ALC262_BASIC] = {
+               .mixers = { alc262_base_mixer },
+               .init_verbs = { alc262_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+       },
+       [ALC262_HIPPO] = {
+               .mixers = { alc262_hippo_mixer },
+               .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_hippo_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_HIPPO_1] = {
+               .mixers = { alc262_hippo1_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x02,
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_hippo1_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_FUJITSU] = {
+               .mixers = { alc262_fujitsu_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
+                               alc262_fujitsu_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_fujitsu_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_fujitsu_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_HP_BPC] = {
+               .mixers = { alc262_HP_BPC_mixer },
+               .init_verbs = { alc262_HP_BPC_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_HP_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_hp_bpc_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_HP_BPC_D7000_WF] = {
+               .mixers = { alc262_HP_BPC_WildWest_mixer },
+               .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_HP_D7000_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_hp_wildwest_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_HP_BPC_D7000_WL] = {
+               .mixers = { alc262_HP_BPC_WildWest_mixer,
+                           alc262_HP_BPC_WildWest_option_mixer },
+               .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_HP_D7000_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_hp_wildwest_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_HP_TC_T5735] = {
+               .mixers = { alc262_hp_t5735_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_hp_t5735_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_HP_RP5700] = {
+               .mixers = { alc262_hp_rp5700_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_hp_rp5700_capture_source,
+        },
+       [ALC262_BENQ_ED8] = {
+               .mixers = { alc262_base_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+       },
+       [ALC262_SONY_ASSAMD] = {
+               .mixers = { alc262_sony_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x02,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_hippo_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_BENQ_T31] = {
+               .mixers = { alc262_benq_t31_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
+                               alc_hp15_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_hippo_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_ULTRA] = {
+               .mixers = { alc262_ultra_mixer },
+               .cap_mixer = alc262_ultra_capture_mixer,
+               .init_verbs = { alc262_ultra_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_ultra_capture_source,
+               .adc_nids = alc262_adc_nids, /* ADC0 */
+               .capsrc_nids = alc262_capsrc_nids,
+               .num_adc_nids = 1, /* single ADC */
+               .unsol_event = alc262_ultra_unsol_event,
+               .init_hook = alc262_ultra_automute,
+       },
+       [ALC262_LENOVO_3000] = {
+               .mixers = { alc262_lenovo_3000_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
+                               alc262_lenovo_3000_unsol_verbs,
+                               alc262_lenovo_3000_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_fujitsu_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_lenovo_3000_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_NEC] = {
+               .mixers = { alc262_nec_mixer },
+               .init_verbs = { alc262_nec_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+       },
+       [ALC262_TOSHIBA_S06] = {
+               .mixers = { alc262_toshiba_s06_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
+                                                       alc262_eapd_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .capsrc_nids = alc262_dmic_capsrc_nids,
+               .dac_nids = alc262_dac_nids,
+               .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
+               .num_adc_nids = 1, /* single ADC */
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_toshiba_s06_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_TOSHIBA_RX1] = {
+               .mixers = { alc262_toshiba_rx1_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_hippo_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC262_TYAN] = {
+               .mixers = { alc262_tyan_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x02,
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc262_tyan_setup,
+               .init_hook = alc_hp_automute,
+       },
+};
+
diff --git a/sound/pci/hda/alc268_quirks.c b/sound/pci/hda/alc268_quirks.c
new file mode 100644 (file)
index 0000000..be58bf2
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * ALC267/ALC268 quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC268 models */
+enum {
+       ALC268_AUTO,
+       ALC267_QUANTA_IL1,
+       ALC268_3ST,
+       ALC268_TOSHIBA,
+       ALC268_ACER,
+       ALC268_ACER_DMIC,
+       ALC268_ACER_ASPIRE_ONE,
+       ALC268_DELL,
+       ALC268_ZEPTO,
+#ifdef CONFIG_SND_DEBUG
+       ALC268_TEST,
+#endif
+       ALC268_MODEL_LAST /* last tag */
+};
+
+/*
+ *  ALC268 channel source setting (2 channel)
+ */
+#define ALC268_DIGOUT_NID      ALC880_DIGOUT_NID
+#define alc268_modes           alc260_modes
+
+static const hda_nid_t alc268_dac_nids[2] = {
+       /* front, hp */
+       0x02, 0x03
+};
+
+static const hda_nid_t alc268_adc_nids[2] = {
+       /* ADC0-1 */
+       0x08, 0x07
+};
+
+static const hda_nid_t alc268_adc_nids_alt[1] = {
+       /* ADC0 */
+       0x08
+};
+
+static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
+
+static const struct snd_kcontrol_new alc268_base_mixer[] = {
+       /* output mixer control */
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
+       { }
+};
+
+static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
+       /* output mixer control */
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
+       { }
+};
+
+static const struct hda_verb alc268_eapd_verbs[] = {
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+/* Toshiba specific */
+static const struct hda_verb alc268_toshiba_verbs[] = {
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
+/* Acer specific */
+/* bind volumes of both NID 0x02 and 0x03 */
+static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static void alc268_acer_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+#define alc268_acer_master_sw_get      alc262_hp_master_sw_get
+#define alc268_acer_master_sw_put      alc262_hp_master_sw_put
+
+static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
+       /* output mixer control */
+       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc268_acer_master_sw_get,
+               .put = alc268_acer_master_sw_put,
+       },
+       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
+       { }
+};
+
+static const struct snd_kcontrol_new alc268_acer_mixer[] = {
+       /* output mixer control */
+       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc268_acer_master_sw_get,
+               .put = alc268_acer_master_sw_put,
+       },
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
+       { }
+};
+
+static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
+       /* output mixer control */
+       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc268_acer_master_sw_get,
+               .put = alc268_acer_master_sw_put,
+       },
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
+       { }
+};
+
+static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
+       { }
+};
+
+static const struct hda_verb alc268_acer_verbs[] = {
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
+/* unsolicited event for HP jack sensing */
+#define alc268_toshiba_setup           alc262_hippo_setup
+
+static void alc268_acer_lc_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x12;
+       spec->auto_mic = 1;
+}
+
+static const struct snd_kcontrol_new alc268_dell_mixer[] = {
+       /* output mixer control */
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { }
+};
+
+static const struct hda_verb alc268_dell_verbs[] = {
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
+       { }
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc268_dell_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { }
+};
+
+static const struct hda_verb alc267_quanta_il1_verbs[] = {
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
+       { }
+};
+
+static void alc267_quanta_il1_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static const struct hda_verb alc268_base_init_verbs[] = {
+       /* Unmute DAC0-1 and set vol = 0 */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /*
+        * Set up output mixers (0x0c - 0x0e)
+        */
+       /* set vol=0 to output mixers */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       /* set PCBEEP vol = 0, mute connections */
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+       /* Unmute Selector 23h,24h and set the default input to mic-in */
+
+       {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       { }
+};
+
+/* only for model=test */
+#ifdef CONFIG_SND_DEBUG
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static const struct hda_verb alc268_volume_init_verbs[] = {
+       /* set output DAC */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       { }
+};
+#endif /* CONFIG_SND_DEBUG */
+
+static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+       _DEFINE_CAPSRC(1),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc268_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
+       _DEFINE_CAPSRC(2),
+       { } /* end */
+};
+
+static const struct hda_input_mux alc268_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x3 },
+       },
+};
+
+static const struct hda_input_mux alc268_acer_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+               { "Line", 0x2 },
+       },
+};
+
+static const struct hda_input_mux alc268_acer_dmic_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x6 },
+               { "Line", 0x2 },
+       },
+};
+
+#ifdef CONFIG_SND_DEBUG
+static const struct snd_kcontrol_new alc268_test_mixer[] = {
+       /* Volume widgets */
+       HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
+       HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
+       HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
+       HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
+       HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
+       HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
+       /* The below appears problematic on some hardwares */
+       /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
+       HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
+
+       /* Modes for retasking pin widgets */
+       ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
+
+       /* Controls for GPIO pins, assuming they are configured as outputs */
+       ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+
+       /* Switches to allow the digital SPDIF output pin to be enabled.
+        * The ALC268 does not have an SPDIF input.
+        */
+       ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
+
+       /* A switch allowing EAPD to be enabled.  Some laptops seem to use
+        * this output to turn on an external amplifier.
+        */
+       ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
+       ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
+
+       { } /* end */
+};
+#endif
+
+/*
+ * configuration and preset
+ */
+static const char * const alc268_models[ALC268_MODEL_LAST] = {
+       [ALC267_QUANTA_IL1]     = "quanta-il1",
+       [ALC268_3ST]            = "3stack",
+       [ALC268_TOSHIBA]        = "toshiba",
+       [ALC268_ACER]           = "acer",
+       [ALC268_ACER_DMIC]      = "acer-dmic",
+       [ALC268_ACER_ASPIRE_ONE]        = "acer-aspire",
+       [ALC268_DELL]           = "dell",
+       [ALC268_ZEPTO]          = "zepto",
+#ifdef CONFIG_SND_DEBUG
+       [ALC268_TEST]           = "test",
+#endif
+       [ALC268_AUTO]           = "auto",
+};
+
+static const struct snd_pci_quirk alc268_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
+       SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
+       SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
+       SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
+       SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
+       SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
+                                               ALC268_ACER_ASPIRE_ONE),
+       SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
+       SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
+       SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
+                       "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
+       /* almost compatible with toshiba but with optional digital outs;
+        * auto-probing seems working fine
+        */
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
+                          ALC268_AUTO),
+       SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
+       SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
+       SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
+       SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
+       {}
+};
+
+/* Toshiba laptops have no unique PCI SSID but only codec SSID */
+static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
+       SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
+       SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
+                          ALC268_TOSHIBA),
+       {}
+};
+
+static const struct alc_config_preset alc268_presets[] = {
+       [ALC267_QUANTA_IL1] = {
+               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
+                           alc268_capture_nosrc_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc267_quanta_il1_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc267_quanta_il1_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC268_3ST] = {
+               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
+                           alc268_beep_mixer },
+               .init_verbs = { alc268_base_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+                .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+                .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC268_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+       },
+       [ALC268_TOSHIBA] = {
+               .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
+                           alc268_beep_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_toshiba_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc268_toshiba_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC268_ACER] = {
+               .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
+                           alc268_beep_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_acer_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
+               .hp_nid = 0x02,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_acer_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc268_acer_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC268_ACER_DMIC] = {
+               .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
+                           alc268_beep_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_acer_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
+               .hp_nid = 0x02,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_acer_dmic_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc268_acer_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC268_ACER_ASPIRE_ONE] = {
+               .mixers = { alc268_acer_aspire_one_mixer,
+                           alc268_beep_mixer,
+                           alc268_capture_nosrc_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_acer_aspire_one_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc268_acer_lc_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC268_DELL] = {
+               .mixers = { alc268_dell_mixer, alc268_beep_mixer,
+                           alc268_capture_nosrc_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_dell_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
+               .hp_nid = 0x02,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc268_dell_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC268_ZEPTO] = {
+               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
+                           alc268_beep_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_toshiba_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC268_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc268_toshiba_setup,
+               .init_hook = alc_inithook,
+       },
+#ifdef CONFIG_SND_DEBUG
+       [ALC268_TEST] = {
+               .mixers = { alc268_test_mixer, alc268_capture_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_volume_init_verbs,
+                               alc268_beep_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC268_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+       },
+#endif
+};
+
diff --git a/sound/pci/hda/alc269_quirks.c b/sound/pci/hda/alc269_quirks.c
new file mode 100644 (file)
index 0000000..14fdcf2
--- /dev/null
@@ -0,0 +1,681 @@
+/*
+ * ALC269/ALC270/ALC275/ALC276 quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC269 models */
+enum {
+       ALC269_AUTO,
+       ALC269_BASIC,
+       ALC269_QUANTA_FL1,
+       ALC269_AMIC,
+       ALC269_DMIC,
+       ALC269VB_AMIC,
+       ALC269VB_DMIC,
+       ALC269_FUJITSU,
+       ALC269_LIFEBOOK,
+       ALC271_ACER,
+       ALC269_MODEL_LAST /* last tag */
+};
+
+/*
+ *  ALC269 channel source setting (2 channel)
+ */
+#define ALC269_DIGOUT_NID      ALC880_DIGOUT_NID
+
+#define alc269_dac_nids                alc260_dac_nids
+
+static const hda_nid_t alc269_adc_nids[1] = {
+       /* ADC1 */
+       0x08,
+};
+
+static const hda_nid_t alc269_capsrc_nids[1] = {
+       0x23,
+};
+
+static const hda_nid_t alc269vb_adc_nids[1] = {
+       /* ADC1 */
+       0x09,
+};
+
+static const hda_nid_t alc269vb_capsrc_nids[1] = {
+       0x22,
+};
+
+#define alc269_modes           alc260_modes
+#define alc269_capture_source  alc880_lg_lw_capture_source
+
+static const struct snd_kcontrol_new alc269_base_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
+       /* output mixer control */
+       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_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 = alc268_acer_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+       },
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { }
+};
+
+static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
+       /* output mixer control */
+       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_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 = alc268_acer_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+       },
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
+       HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
+       { }
+};
+
+static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc269_asus_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+/* capture mixer elements */
+static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       { } /* end */
+};
+
+/* FSC amilo */
+#define alc269_fujitsu_mixer   alc269_laptop_mixer
+
+static const struct hda_verb alc269_quanta_fl1_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       { }
+};
+
+static const struct hda_verb alc269_lifebook_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
+{
+       alc_hp_automute(codec);
+
+       snd_hda_codec_write(codec, 0x20, 0,
+                       AC_VERB_SET_COEF_INDEX, 0x0c);
+       snd_hda_codec_write(codec, 0x20, 0,
+                       AC_VERB_SET_PROC_COEF, 0x680);
+
+       snd_hda_codec_write(codec, 0x20, 0,
+                       AC_VERB_SET_COEF_INDEX, 0x0c);
+       snd_hda_codec_write(codec, 0x20, 0,
+                       AC_VERB_SET_PROC_COEF, 0x480);
+}
+
+#define alc269_lifebook_speaker_automute \
+       alc269_quanta_fl1_speaker_automute
+
+static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
+{
+       unsigned int present_laptop;
+       unsigned int present_dock;
+
+       present_laptop  = snd_hda_jack_detect(codec, 0x18);
+       present_dock    = snd_hda_jack_detect(codec, 0x1b);
+
+       /* Laptop mic port overrides dock mic port, design decision */
+       if (present_dock)
+               snd_hda_codec_write(codec, 0x23, 0,
+                               AC_VERB_SET_CONNECT_SEL, 0x3);
+       if (present_laptop)
+               snd_hda_codec_write(codec, 0x23, 0,
+                               AC_VERB_SET_CONNECT_SEL, 0x0);
+       if (!present_dock && !present_laptop)
+               snd_hda_codec_write(codec, 0x23, 0,
+                               AC_VERB_SET_CONNECT_SEL, 0x1);
+}
+
+static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
+                                   unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC_HP_EVENT:
+               alc269_quanta_fl1_speaker_automute(codec);
+               break;
+       case ALC_MIC_EVENT:
+               alc_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc269_lifebook_unsol_event(struct hda_codec *codec,
+                                       unsigned int res)
+{
+       if ((res >> 26) == ALC_HP_EVENT)
+               alc269_lifebook_speaker_automute(codec);
+       if ((res >> 26) == ALC_MIC_EVENT)
+               alc269_lifebook_mic_autoswitch(codec);
+}
+
+static void alc269_quanta_fl1_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
+{
+       alc269_quanta_fl1_speaker_automute(codec);
+       alc_mic_automute(codec);
+}
+
+static void alc269_lifebook_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.hp_pins[1] = 0x1a;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+}
+
+static void alc269_lifebook_init_hook(struct hda_codec *codec)
+{
+       alc269_lifebook_speaker_automute(codec);
+       alc269_lifebook_mic_autoswitch(codec);
+}
+
+static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc271_acer_dmic_verbs[] = {
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 6},
+       { }
+};
+
+static void alc269_laptop_amic_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+static void alc269_laptop_dmic_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x12;
+       spec->auto_mic = 1;
+}
+
+static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x21;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x21;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x12;
+       spec->auto_mic = 1;
+}
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static const struct hda_verb alc269_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /*
+        * Set up output mixers (0x02 - 0x03)
+        */
+       /* set vol=0 to output mixers */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* FIXME: use Mux-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* set EAPD */
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+static const struct hda_verb alc269vb_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /*
+        * Set up output mixers (0x02 - 0x03)
+        */
+       /* set vol=0 to output mixers */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* FIXME: use Mux-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* set EAPD */
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+/*
+ * configuration and preset
+ */
+static const char * const alc269_models[ALC269_MODEL_LAST] = {
+       [ALC269_BASIC]                  = "basic",
+       [ALC269_QUANTA_FL1]             = "quanta",
+       [ALC269_AMIC]                   = "laptop-amic",
+       [ALC269_DMIC]                   = "laptop-dmic",
+       [ALC269_FUJITSU]                = "fujitsu",
+       [ALC269_LIFEBOOK]               = "lifebook",
+       [ALC269_AUTO]                   = "auto",
+};
+
+static const struct snd_pci_quirk alc269_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
+       SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
+       SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
+                     ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
+                     ALC269_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
+                     ALC269_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
+       SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
+       SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
+       SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
+       SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
+       SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
+       SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
+       SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
+       {}
+};
+
+static const struct alc_config_preset alc269_presets[] = {
+       [ALC269_BASIC] = {
+               .mixers = { alc269_base_mixer },
+               .init_verbs = { alc269_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .input_mux = &alc269_capture_source,
+       },
+       [ALC269_QUANTA_FL1] = {
+               .mixers = { alc269_quanta_fl1_mixer },
+               .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .input_mux = &alc269_capture_source,
+               .unsol_event = alc269_quanta_fl1_unsol_event,
+               .setup = alc269_quanta_fl1_setup,
+               .init_hook = alc269_quanta_fl1_init_hook,
+       },
+       [ALC269_AMIC] = {
+               .mixers = { alc269_laptop_mixer },
+               .cap_mixer = alc269_laptop_analog_capture_mixer,
+               .init_verbs = { alc269_init_verbs,
+                               alc269_laptop_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc269_laptop_amic_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC269_DMIC] = {
+               .mixers = { alc269_laptop_mixer },
+               .cap_mixer = alc269_laptop_digital_capture_mixer,
+               .init_verbs = { alc269_init_verbs,
+                               alc269_laptop_dmic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc269_laptop_dmic_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC269VB_AMIC] = {
+               .mixers = { alc269vb_laptop_mixer },
+               .cap_mixer = alc269vb_laptop_analog_capture_mixer,
+               .init_verbs = { alc269vb_init_verbs,
+                               alc269vb_laptop_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc269vb_laptop_amic_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC269VB_DMIC] = {
+               .mixers = { alc269vb_laptop_mixer },
+               .cap_mixer = alc269vb_laptop_digital_capture_mixer,
+               .init_verbs = { alc269vb_init_verbs,
+                               alc269vb_laptop_dmic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc269vb_laptop_dmic_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC269_FUJITSU] = {
+               .mixers = { alc269_fujitsu_mixer },
+               .cap_mixer = alc269_laptop_digital_capture_mixer,
+               .init_verbs = { alc269_init_verbs,
+                               alc269_laptop_dmic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc269_laptop_dmic_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC269_LIFEBOOK] = {
+               .mixers = { alc269_lifebook_mixer },
+               .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .input_mux = &alc269_capture_source,
+               .unsol_event = alc269_lifebook_unsol_event,
+               .setup = alc269_lifebook_setup,
+               .init_hook = alc269_lifebook_init_hook,
+       },
+       [ALC271_ACER] = {
+               .mixers = { alc269_asus_mixer },
+               .cap_mixer = alc269vb_laptop_digital_capture_mixer,
+               .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
+               .adc_nids = alc262_dmic_adc_nids,
+               .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
+               .capsrc_nids = alc262_dmic_capsrc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .input_mux = &alc269_capture_source,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc269vb_laptop_dmic_setup,
+               .init_hook = alc_inithook,
+       },
+};
+
diff --git a/sound/pci/hda/alc662_quirks.c b/sound/pci/hda/alc662_quirks.c
new file mode 100644 (file)
index 0000000..e69a6ea
--- /dev/null
@@ -0,0 +1,1408 @@
+/*
+ * ALC662/ALC663/ALC665/ALC670 quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC662 models */
+enum {
+       ALC662_AUTO,
+       ALC662_3ST_2ch_DIG,
+       ALC662_3ST_6ch_DIG,
+       ALC662_3ST_6ch,
+       ALC662_5ST_DIG,
+       ALC662_LENOVO_101E,
+       ALC662_ASUS_EEEPC_P701,
+       ALC662_ASUS_EEEPC_EP20,
+       ALC663_ASUS_M51VA,
+       ALC663_ASUS_G71V,
+       ALC663_ASUS_H13,
+       ALC663_ASUS_G50V,
+       ALC662_ECS,
+       ALC663_ASUS_MODE1,
+       ALC662_ASUS_MODE2,
+       ALC663_ASUS_MODE3,
+       ALC663_ASUS_MODE4,
+       ALC663_ASUS_MODE5,
+       ALC663_ASUS_MODE6,
+       ALC663_ASUS_MODE7,
+       ALC663_ASUS_MODE8,
+       ALC272_DELL,
+       ALC272_DELL_ZM1,
+       ALC272_SAMSUNG_NC10,
+       ALC662_MODEL_LAST,
+};
+
+#define ALC662_DIGOUT_NID      0x06
+#define ALC662_DIGIN_NID       0x0a
+
+static const hda_nid_t alc662_dac_nids[3] = {
+       /* front, rear, clfe */
+       0x02, 0x03, 0x04
+};
+
+static const hda_nid_t alc272_dac_nids[2] = {
+       0x02, 0x03
+};
+
+static const hda_nid_t alc662_adc_nids[2] = {
+       /* ADC1-2 */
+       0x09, 0x08
+};
+
+static const hda_nid_t alc272_adc_nids[1] = {
+       /* ADC1-2 */
+       0x08,
+};
+
+static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
+static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
+
+
+/* input MUX */
+/* FIXME: should be a matrix-type input source selection */
+static const struct hda_input_mux alc662_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
+static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x1 },
+               { "Line", 0x2 },
+       },
+};
+
+static const struct hda_input_mux alc663_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+       },
+};
+
+#if 0 /* set to 1 for testing other input sources below */
+static const struct hda_input_mux alc272_nc10_capture_source = {
+       .num_items = 16,
+       .items = {
+               { "Autoselect Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+               { "In-0x02", 0x2 },
+               { "In-0x03", 0x3 },
+               { "In-0x04", 0x4 },
+               { "In-0x05", 0x5 },
+               { "In-0x06", 0x6 },
+               { "In-0x07", 0x7 },
+               { "In-0x08", 0x8 },
+               { "In-0x09", 0x9 },
+               { "In-0x0a", 0x0a },
+               { "In-0x0b", 0x0b },
+               { "In-0x0c", 0x0c },
+               { "In-0x0d", 0x0d },
+               { "In-0x0e", 0x0e },
+               { "In-0x0f", 0x0f },
+       },
+};
+#endif
+
+/*
+ * 2ch mode
+ */
+static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
+       { 2, NULL }
+};
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc662_3ST_ch2_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc662_3ST_ch6_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
+       { 2, alc662_3ST_ch2_init },
+       { 6, alc662_3ST_ch6_init },
+};
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc662_sixstack_ch6_init[] = {
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc662_sixstack_ch8_init[] = {
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc662_5stack_modes[2] = {
+       { 2, alc662_sixstack_ch6_init },
+       { 6, alc662_sixstack_ch8_init },
+};
+
+/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+
+static const struct snd_kcontrol_new alc662_base_mixer[] = {
+       /* output mixer control */
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+       /*Input mixer control */
+       HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
+
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+       { } /* end */
+};
+
+static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume",
+                               &alc663_asus_two_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
+       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
+       HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
+       HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
+       HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
+       HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+
+static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+static const struct hda_verb alc662_init_verbs[] = {
+       /* ADC: mute amp left and right */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* Front Pin: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Rear Pin: output 1 (0x0d) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* CLFE Pin: output 2 (0x0e) */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Mic (rear) pin: input vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin: input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line-2 In: Headphone output (output 0 - 0x0c) */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* CD pin widget for input */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       { }
+};
+
+static const struct hda_verb alc662_eapd_init_verbs[] = {
+       /* always trun on EAPD */
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+static const struct hda_verb alc662_sue_init_verbs[] = {
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+/* Set Unsolicited Event*/
+static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc663_m51va_init_verbs[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x0},   /* Headphone */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},   /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc663_g71v_init_verbs[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
+       /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
+
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc663_g50v_init_verbs[] = {
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc662_ecs_init_verbs[] = {
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc272_dell_init_verbs[] = {
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc663_mode7_init_verbs[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct hda_verb alc663_mode8_init_verbs[] = {
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {}
+};
+
+static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static void alc662_lenovo_101e_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.line_out_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->detect_line = 1;
+       spec->automute_lines = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc662_eeepc_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc262_hippo1_setup(codec);
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x1b;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc663_m51va_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x21;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x12;
+       spec->auto_mic = 1;
+}
+
+/* ***************** Mode1 ******************************/
+static void alc663_mode1_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x21;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+/* ***************** Mode2 ******************************/
+static void alc662_mode2_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+/* ***************** Mode3 ******************************/
+static void alc663_mode3_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x21;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+/* ***************** Mode4 ******************************/
+static void alc663_mode4_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x21;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute_mixer_nid[1] = 0x0e;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+/* ***************** Mode5 ******************************/
+static void alc663_mode5_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute_mixer_nid[1] = 0x0e;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+/* ***************** Mode6 ******************************/
+static void alc663_mode6_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute_mixer_nid[0] = 0x0c;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+/* ***************** Mode7 ******************************/
+static void alc663_mode7_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.hp_pins[0] = 0x21;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x17;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+}
+
+/* ***************** Mode8 ******************************/
+static void alc663_mode8_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x21;
+       spec->autocfg.hp_pins[1] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x17;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_PIN;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x12;
+       spec->auto_mic = 1;
+}
+
+static void alc663_g71v_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x21;
+       spec->autocfg.line_out_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+       spec->detect_line = 1;
+       spec->automute_lines = 1;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x12;
+       spec->auto_mic = 1;
+}
+
+#define alc663_g50v_setup      alc663_m51va_setup
+
+static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
+
+       HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
+       /* Master Playback automatically created from Speaker and Headphone */
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+
+/*
+ * configuration and preset
+ */
+static const char * const alc662_models[ALC662_MODEL_LAST] = {
+       [ALC662_3ST_2ch_DIG]    = "3stack-dig",
+       [ALC662_3ST_6ch_DIG]    = "3stack-6ch-dig",
+       [ALC662_3ST_6ch]        = "3stack-6ch",
+       [ALC662_5ST_DIG]        = "5stack-dig",
+       [ALC662_LENOVO_101E]    = "lenovo-101e",
+       [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
+       [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
+       [ALC662_ECS] = "ecs",
+       [ALC663_ASUS_M51VA] = "m51va",
+       [ALC663_ASUS_G71V] = "g71v",
+       [ALC663_ASUS_H13] = "h13",
+       [ALC663_ASUS_G50V] = "g50v",
+       [ALC663_ASUS_MODE1] = "asus-mode1",
+       [ALC662_ASUS_MODE2] = "asus-mode2",
+       [ALC663_ASUS_MODE3] = "asus-mode3",
+       [ALC663_ASUS_MODE4] = "asus-mode4",
+       [ALC663_ASUS_MODE5] = "asus-mode5",
+       [ALC663_ASUS_MODE6] = "asus-mode6",
+       [ALC663_ASUS_MODE7] = "asus-mode7",
+       [ALC663_ASUS_MODE8] = "asus-mode8",
+       [ALC272_DELL]           = "dell",
+       [ALC272_DELL_ZM1]       = "dell-zm1",
+       [ALC272_SAMSUNG_NC10]   = "samsung-nc10",
+       [ALC662_AUTO]           = "auto",
+};
+
+static const struct snd_pci_quirk alc662_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
+       SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
+       SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
+       SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
+       SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
+       SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
+       SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
+       SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
+       SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
+       /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
+       SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
+       /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
+       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
+       SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
+       SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
+       SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
+       SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
+       SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
+                     ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
+       SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
+       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
+                     ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
+       SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
+       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
+       SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
+                                       ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
+                          ALC663_ASUS_H13),
+       SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
+       {}
+};
+
+static const struct alc_config_preset alc662_presets[] = {
+       [ALC662_3ST_2ch_DIG] = {
+               .mixers = { alc662_3ST_2ch_mixer },
+               .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .dig_in_nid = ALC662_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_capture_source,
+       },
+       [ALC662_3ST_6ch_DIG] = {
+               .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
+               .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .dig_in_nid = ALC662_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
+               .channel_mode = alc662_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc662_capture_source,
+       },
+       [ALC662_3ST_6ch] = {
+               .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
+               .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
+               .channel_mode = alc662_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc662_capture_source,
+       },
+       [ALC662_5ST_DIG] = {
+               .mixers = { alc662_base_mixer, alc662_chmode_mixer },
+               .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .dig_in_nid = ALC662_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
+               .channel_mode = alc662_5stack_modes,
+               .input_mux = &alc662_capture_source,
+       },
+       [ALC662_LENOVO_101E] = {
+               .mixers = { alc662_lenovo_101e_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc662_sue_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_lenovo_101e_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc662_lenovo_101e_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC662_ASUS_EEEPC_P701] = {
+               .mixers = { alc662_eeepc_p701_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc662_eeepc_sue_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc662_eeepc_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC662_ASUS_EEEPC_EP20] = {
+               .mixers = { alc662_eeepc_ep20_mixer,
+                           alc662_chmode_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc662_eeepc_ep20_sue_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
+               .channel_mode = alc662_3ST_6ch_modes,
+               .input_mux = &alc662_lenovo_101e_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc662_eeepc_ep20_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC662_ECS] = {
+               .mixers = { alc662_ecs_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc662_ecs_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc662_eeepc_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_M51VA] = {
+               .mixers = { alc663_m51va_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_m51va_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_m51va_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_G71V] = {
+               .mixers = { alc663_g71v_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_g71v_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_g71v_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_H13] = {
+               .mixers = { alc663_m51va_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_m51va_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .setup = alc663_m51va_setup,
+               .unsol_event = alc_sku_unsol_event,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_G50V] = {
+               .mixers = { alc663_g50v_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_g50v_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
+               .channel_mode = alc662_3ST_6ch_modes,
+               .input_mux = &alc663_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_g50v_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_MODE1] = {
+               .mixers = { alc663_m51va_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_21jd_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_mode1_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC662_ASUS_MODE2] = {
+               .mixers = { alc662_1bjd_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc662_1bjd_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc662_mode2_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_MODE3] = {
+               .mixers = { alc663_two_hp_m1_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_two_hp_amic_m1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_mode3_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_MODE4] = {
+               .mixers = { alc663_asus_21jd_clfe_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_21jd_amic_init_verbs},
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_mode4_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_MODE5] = {
+               .mixers = { alc663_asus_15jd_clfe_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_15jd_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_mode5_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_MODE6] = {
+               .mixers = { alc663_two_hp_m2_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_two_hp_amic_m2_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_mode6_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_MODE7] = {
+               .mixers = { alc663_mode7_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_mode7_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_mode7_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC663_ASUS_MODE8] = {
+               .mixers = { alc663_mode8_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_mode8_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_mode8_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC272_DELL] = {
+               .mixers = { alc663_m51va_mixer },
+               .cap_mixer = alc272_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc272_dell_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc272_dac_nids),
+               .dac_nids = alc272_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .adc_nids = alc272_adc_nids,
+               .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
+               .capsrc_nids = alc272_capsrc_nids,
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_m51va_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC272_DELL_ZM1] = {
+               .mixers = { alc663_m51va_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc272_dell_zm1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc272_dac_nids),
+               .dac_nids = alc272_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .adc_nids = alc662_adc_nids,
+               .num_adc_nids = 1,
+               .capsrc_nids = alc662_capsrc_nids,
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_m51va_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC272_SAMSUNG_NC10] = {
+               .mixers = { alc272_nc10_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eapd_init_verbs,
+                               alc663_21jd_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc272_dac_nids),
+               .dac_nids = alc272_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               /*.input_mux = &alc272_nc10_capture_source,*/
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc663_mode4_setup,
+               .init_hook = alc_inithook,
+       },
+};
+
+
diff --git a/sound/pci/hda/alc680_quirks.c b/sound/pci/hda/alc680_quirks.c
new file mode 100644 (file)
index 0000000..0eeb227
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * ALC680 quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC680 models */
+enum {
+       ALC680_AUTO,
+       ALC680_BASE,
+       ALC680_MODEL_LAST,
+};
+
+#define ALC680_DIGIN_NID       ALC880_DIGIN_NID
+#define ALC680_DIGOUT_NID      ALC880_DIGOUT_NID
+#define alc680_modes           alc260_modes
+
+static const hda_nid_t alc680_dac_nids[3] = {
+       /* Lout1, Lout2, hp */
+       0x02, 0x03, 0x04
+};
+
+static const hda_nid_t alc680_adc_nids[3] = {
+       /* ADC0-2 */
+       /* DMIC, MIC, Line-in*/
+       0x07, 0x08, 0x09
+};
+
+/*
+ * Analog capture ADC cgange
+ */
+static hda_nid_t alc680_get_cur_adc(struct hda_codec *codec)
+{
+       static hda_nid_t pins[] = {0x18, 0x19};
+       static hda_nid_t adcs[] = {0x08, 0x09};
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pins); i++) {
+               if (!is_jack_detectable(codec, pins[i]))
+                       continue;
+               if (snd_hda_jack_detect(codec, pins[i]))
+                       return adcs[i];
+       }
+       return 0x07;
+}
+
+static void alc680_rec_autoswitch(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t nid = alc680_get_cur_adc(codec);
+       if (spec->cur_adc && nid != spec->cur_adc) {
+               __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+               spec->cur_adc = nid;
+               snd_hda_codec_setup_stream(codec, nid,
+                                          spec->cur_adc_stream_tag, 0,
+                                          spec->cur_adc_format);
+       }
+}
+
+static int alc680_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 alc_spec *spec = codec->spec;
+       hda_nid_t nid = alc680_get_cur_adc(codec);
+
+       spec->cur_adc = nid;
+       spec->cur_adc_stream_tag = stream_tag;
+       spec->cur_adc_format = format;
+       snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+       return 0;
+}
+
+static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                     struct hda_codec *codec,
+                                     struct snd_pcm_substream *substream)
+{
+       struct alc_spec *spec = codec->spec;
+       snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+       spec->cur_adc = 0;
+       return 0;
+}
+
+static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
+       .substreams = 1, /* can be overridden */
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in alc_build_pcms */
+       .ops = {
+               .prepare = alc680_capture_pcm_prepare,
+               .cleanup = alc680_capture_pcm_cleanup
+       },
+};
+
+static const struct snd_kcontrol_new alc680_base_mixer[] = {
+       /* output mixer control */
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
+       { }
+};
+
+static const struct hda_bind_ctls alc680_bind_cap_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+               0
+       },
+};
+
+static const struct hda_bind_ctls alc680_bind_cap_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+               0
+       },
+};
+
+static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
+       HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
+       HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
+       { } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static const struct hda_verb alc680_init_verbs[] = {
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT   | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT  | AC_USRSP_EN},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT  | AC_USRSP_EN},
+
+       { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc680_base_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x16;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x15;
+       spec->autocfg.num_inputs = 2;
+       spec->autocfg.inputs[0].pin = 0x18;
+       spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
+       spec->autocfg.inputs[1].pin = 0x19;
+       spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc680_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       if ((res >> 26) == ALC_HP_EVENT)
+               alc_hp_automute(codec);
+       if ((res >> 26) == ALC_MIC_EVENT)
+               alc680_rec_autoswitch(codec);
+}
+
+static void alc680_inithook(struct hda_codec *codec)
+{
+       alc_hp_automute(codec);
+       alc680_rec_autoswitch(codec);
+}
+
+/*
+ * configuration and preset
+ */
+static const char * const alc680_models[ALC680_MODEL_LAST] = {
+       [ALC680_BASE]           = "base",
+       [ALC680_AUTO]           = "auto",
+};
+
+static const struct snd_pci_quirk alc680_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
+       {}
+};
+
+static const struct alc_config_preset alc680_presets[] = {
+       [ALC680_BASE] = {
+               .mixers = { alc680_base_mixer },
+               .cap_mixer =  alc680_master_capture_mixer,
+               .init_verbs = { alc680_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc680_dac_nids),
+               .dac_nids = alc680_dac_nids,
+               .dig_out_nid = ALC680_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc680_modes),
+               .channel_mode = alc680_modes,
+               .unsol_event = alc680_unsol_event,
+               .setup = alc680_base_setup,
+               .init_hook = alc680_inithook,
+
+       },
+};
diff --git a/sound/pci/hda/alc861_quirks.c b/sound/pci/hda/alc861_quirks.c
new file mode 100644 (file)
index 0000000..d719ec6
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ * ALC660/ALC861 quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC861 models */
+enum {
+       ALC861_AUTO,
+       ALC861_3ST,
+       ALC660_3ST,
+       ALC861_3ST_DIG,
+       ALC861_6ST_DIG,
+       ALC861_UNIWILL_M31,
+       ALC861_TOSHIBA,
+       ALC861_ASUS,
+       ALC861_ASUS_LAPTOP,
+       ALC861_MODEL_LAST,
+};
+
+/*
+ *  ALC861 channel source setting (2/6 channel selection for 3-stack)
+ */
+
+/*
+ * set the path ways for 2 channel output
+ * need to set the codec line out and mic 1 pin widgets to inputs
+ */
+static const struct hda_verb alc861_threestack_ch2_init[] = {
+       /* set pin widget 1Ah (line in) for input */
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* set pin widget 18h (mic1/2) for input, for mic also enable
+        * the vref
+        */
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
+#if 0
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
+#endif
+       { } /* end */
+};
+/*
+ * 6ch mode
+ * need to set the codec line out and mic 1 pin widgets to outputs
+ */
+static const struct hda_verb alc861_threestack_ch6_init[] = {
+       /* set pin widget 1Ah (line in) for output (Back Surround)*/
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       /* set pin widget 18h (mic1) for output (CLFE)*/
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+
+       { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
+
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+#if 0
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
+#endif
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc861_threestack_modes[2] = {
+       { 2, alc861_threestack_ch2_init },
+       { 6, alc861_threestack_ch6_init },
+};
+/* Set mic1 as input and unmute the mixer */
+static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
+       { } /* end */
+};
+/* Set mic1 as output and mute mixer */
+static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
+       { 2, alc861_uniwill_m31_ch2_init },
+       { 4, alc861_uniwill_m31_ch4_init },
+};
+
+/* Set mic1 and line-in as input and unmute the mixer */
+static const struct hda_verb alc861_asus_ch2_init[] = {
+       /* set pin widget 1Ah (line in) for input */
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* set pin widget 18h (mic1/2) for input, for mic also enable
+        * the vref
+        */
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
+#if 0
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
+#endif
+       { } /* end */
+};
+/* Set mic1 nad line-in as output and mute mixer */
+static const struct hda_verb alc861_asus_ch6_init[] = {
+       /* set pin widget 1Ah (line in) for output (Back Surround)*/
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
+       /* set pin widget 18h (mic1) for output (CLFE)*/
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
+       { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
+
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+#if 0
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
+#endif
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc861_asus_modes[2] = {
+       { 2, alc861_asus_ch2_init },
+       { 6, alc861_asus_ch6_init },
+};
+
+/* patch-ALC861 */
+
+static const struct snd_kcontrol_new alc861_base_mixer[] = {
+        /* output mixer control */
+       HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
+
+        /*Input mixer control */
+       /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
+          HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
+
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
+        /* output mixer control */
+       HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+       /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
+
+       /* Input mixer control */
+       /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
+          HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
+
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+                .private_value = ARRAY_SIZE(alc861_threestack_modes),
+       },
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
+        /* output mixer control */
+       HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
+        /* output mixer control */
+       HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+       /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
+
+       /* Input mixer control */
+       /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
+          HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
+
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+                .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
+       },
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc861_asus_mixer[] = {
+        /* output mixer control */
+       HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
+
+       /* Input mixer control */
+       HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
+
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+                .private_value = ARRAY_SIZE(alc861_asus_modes),
+       },
+       { }
+};
+
+/* additional mixer */
+static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+       { }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static const struct hda_verb alc861_base_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       /* port-A for surround (rear panel) */
+       { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-B for mic-in (rear panel) with vref */
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* port-C for line-in (rear panel) */
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* port-D for Front */
+       { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-E for HP out (front panel) */
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+       /* route front PCM to HP */
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-F for mic-in (front panel) with vref */
+       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* port-G for CLFE (rear panel) */
+       { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-H for side (rear panel) */
+       { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* CD-in */
+       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* route front mic to ADC1*/
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Unmute DAC0~3 & spdif out*/
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Unmute Mixer 14 (mic) 1c (Line in)*/
+       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* Unmute Stereo Mixer 15 */
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
+
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* hp used DAC 3 (Front) */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+
+       { }
+};
+
+static const struct hda_verb alc861_threestack_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       /* port-A for surround (rear panel) */
+       { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       /* port-B for mic-in (rear panel) with vref */
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* port-C for line-in (rear panel) */
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* port-D for Front */
+       { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-E for HP out (front panel) */
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+       /* route front PCM to HP */
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-F for mic-in (front panel) with vref */
+       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* port-G for CLFE (rear panel) */
+       { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       /* port-H for side (rear panel) */
+       { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       /* CD-in */
+       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* route front mic to ADC1*/
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* Unmute DAC0~3 & spdif out*/
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Unmute Mixer 14 (mic) 1c (Line in)*/
+       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* Unmute Stereo Mixer 15 */
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
+
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* hp used DAC 3 (Front) */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       { }
+};
+
+static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       /* port-A for surround (rear panel) */
+       { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       /* port-B for mic-in (rear panel) with vref */
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* port-C for line-in (rear panel) */
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* port-D for Front */
+       { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-E for HP out (front panel) */
+       /* this has to be set to VREF80 */
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* route front PCM to HP */
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-F for mic-in (front panel) with vref */
+       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* port-G for CLFE (rear panel) */
+       { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       /* port-H for side (rear panel) */
+       { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       /* CD-in */
+       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* route front mic to ADC1*/
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* Unmute DAC0~3 & spdif out*/
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Unmute Mixer 14 (mic) 1c (Line in)*/
+       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* Unmute Stereo Mixer 15 */
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
+
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* hp used DAC 3 (Front) */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       { }
+};
+
+static const struct hda_verb alc861_asus_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       /* port-A for surround (rear panel)
+        * according to codec#0 this is the HP jack
+        */
+       { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
+       /* route front PCM to HP */
+       { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       /* port-B for mic-in (rear panel) with vref */
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* port-C for line-in (rear panel) */
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* port-D for Front */
+       { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-E for HP out (front panel) */
+       /* this has to be set to VREF80 */
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* route front PCM to HP */
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       /* port-F for mic-in (front panel) with vref */
+       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+       /* port-G for CLFE (rear panel) */
+       { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       /* port-H for side (rear panel) */
+       { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+       /* CD-in */
+       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* route front mic to ADC1*/
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* Unmute DAC0~3 & spdif out*/
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Unmute Mixer 14 (mic) 1c (Line in)*/
+       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* Unmute Stereo Mixer 15 */
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
+
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* hp used DAC 3 (Front) */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       { }
+};
+
+/* additional init verbs for ASUS laptops */
+static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
+       { }
+};
+
+static const struct hda_verb alc861_toshiba_init_verbs[] = {
+       {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+
+       { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc861_toshiba_automute(struct hda_codec *codec)
+{
+       unsigned int present = snd_hda_jack_detect(codec, 0x0f);
+
+       snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
+                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
+                                HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
+}
+
+static void alc861_toshiba_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       if ((res >> 26) == ALC_HP_EVENT)
+               alc861_toshiba_automute(codec);
+}
+
+#define ALC861_DIGOUT_NID      0x07
+
+static const struct hda_channel_mode alc861_8ch_modes[1] = {
+       { 8, NULL }
+};
+
+static const hda_nid_t alc861_dac_nids[4] = {
+       /* front, surround, clfe, side */
+       0x03, 0x06, 0x05, 0x04
+};
+
+static const hda_nid_t alc660_dac_nids[3] = {
+       /* front, clfe, surround */
+       0x03, 0x05, 0x06
+};
+
+static const hda_nid_t alc861_adc_nids[1] = {
+       /* ADC0-2 */
+       0x08,
+};
+
+static const struct hda_input_mux alc861_capture_source = {
+       .num_items = 5,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x3 },
+               { "Line", 0x1 },
+               { "CD", 0x4 },
+               { "Mixer", 0x5 },
+       },
+};
+
+/*
+ * configuration and preset
+ */
+static const char * const alc861_models[ALC861_MODEL_LAST] = {
+       [ALC861_3ST]            = "3stack",
+       [ALC660_3ST]            = "3stack-660",
+       [ALC861_3ST_DIG]        = "3stack-dig",
+       [ALC861_6ST_DIG]        = "6stack-dig",
+       [ALC861_UNIWILL_M31]    = "uniwill-m31",
+       [ALC861_TOSHIBA]        = "toshiba",
+       [ALC861_ASUS]           = "asus",
+       [ALC861_ASUS_LAPTOP]    = "asus-laptop",
+       [ALC861_AUTO]           = "auto",
+};
+
+static const struct snd_pci_quirk alc861_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
+       SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
+       SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
+       SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+       SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
+       SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
+       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
+       /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
+        *        Any other models that need this preset?
+        */
+       /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
+       SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
+       SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
+       SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
+       SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+       SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
+       /* FIXME: the below seems conflict */
+       /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
+       SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
+       SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
+       {}
+};
+
+static const struct alc_config_preset alc861_presets[] = {
+       [ALC861_3ST] = {
+               .mixers = { alc861_3ST_mixer },
+               .init_verbs = { alc861_threestack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+               .dac_nids = alc861_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
+               .channel_mode = alc861_threestack_modes,
+               .need_dac_fix = 1,
+               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+               .adc_nids = alc861_adc_nids,
+               .input_mux = &alc861_capture_source,
+       },
+       [ALC861_3ST_DIG] = {
+               .mixers = { alc861_base_mixer },
+               .init_verbs = { alc861_threestack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+               .dac_nids = alc861_dac_nids,
+               .dig_out_nid = ALC861_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
+               .channel_mode = alc861_threestack_modes,
+               .need_dac_fix = 1,
+               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+               .adc_nids = alc861_adc_nids,
+               .input_mux = &alc861_capture_source,
+       },
+       [ALC861_6ST_DIG] = {
+               .mixers = { alc861_base_mixer },
+               .init_verbs = { alc861_base_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+               .dac_nids = alc861_dac_nids,
+               .dig_out_nid = ALC861_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
+               .channel_mode = alc861_8ch_modes,
+               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+               .adc_nids = alc861_adc_nids,
+               .input_mux = &alc861_capture_source,
+       },
+       [ALC660_3ST] = {
+               .mixers = { alc861_3ST_mixer },
+               .init_verbs = { alc861_threestack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc660_dac_nids),
+               .dac_nids = alc660_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
+               .channel_mode = alc861_threestack_modes,
+               .need_dac_fix = 1,
+               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+               .adc_nids = alc861_adc_nids,
+               .input_mux = &alc861_capture_source,
+       },
+       [ALC861_UNIWILL_M31] = {
+               .mixers = { alc861_uniwill_m31_mixer },
+               .init_verbs = { alc861_uniwill_m31_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+               .dac_nids = alc861_dac_nids,
+               .dig_out_nid = ALC861_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
+               .channel_mode = alc861_uniwill_m31_modes,
+               .need_dac_fix = 1,
+               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+               .adc_nids = alc861_adc_nids,
+               .input_mux = &alc861_capture_source,
+       },
+       [ALC861_TOSHIBA] = {
+               .mixers = { alc861_toshiba_mixer },
+               .init_verbs = { alc861_base_init_verbs,
+                               alc861_toshiba_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+               .dac_nids = alc861_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+               .adc_nids = alc861_adc_nids,
+               .input_mux = &alc861_capture_source,
+               .unsol_event = alc861_toshiba_unsol_event,
+               .init_hook = alc861_toshiba_automute,
+       },
+       [ALC861_ASUS] = {
+               .mixers = { alc861_asus_mixer },
+               .init_verbs = { alc861_asus_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+               .dac_nids = alc861_dac_nids,
+               .dig_out_nid = ALC861_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
+               .channel_mode = alc861_asus_modes,
+               .need_dac_fix = 1,
+               .hp_nid = 0x06,
+               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+               .adc_nids = alc861_adc_nids,
+               .input_mux = &alc861_capture_source,
+       },
+       [ALC861_ASUS_LAPTOP] = {
+               .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
+               .init_verbs = { alc861_asus_init_verbs,
+                               alc861_asus_laptop_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+               .dac_nids = alc861_dac_nids,
+               .dig_out_nid = ALC861_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .need_dac_fix = 1,
+               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+               .adc_nids = alc861_adc_nids,
+               .input_mux = &alc861_capture_source,
+       },
+};
+
diff --git a/sound/pci/hda/alc861vd_quirks.c b/sound/pci/hda/alc861vd_quirks.c
new file mode 100644 (file)
index 0000000..8f28450
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * ALC660-VD/ALC861-VD quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC861-VD models */
+enum {
+       ALC861VD_AUTO,
+       ALC660VD_3ST,
+       ALC660VD_3ST_DIG,
+       ALC660VD_ASUS_V1S,
+       ALC861VD_3ST,
+       ALC861VD_3ST_DIG,
+       ALC861VD_6ST_DIG,
+       ALC861VD_LENOVO,
+       ALC861VD_DALLAS,
+       ALC861VD_HP,
+       ALC861VD_MODEL_LAST,
+};
+
+#define ALC861VD_DIGOUT_NID    0x06
+
+static const hda_nid_t alc861vd_dac_nids[4] = {
+       /* front, surr, clfe, side surr */
+       0x02, 0x03, 0x04, 0x05
+};
+
+/* dac_nids for ALC660vd are in a different order - according to
+ * Realtek's driver.
+ * This should probably result in a different mixer for 6stack models
+ * of ALC660vd codecs, but for now there is only 3stack mixer
+ * - and it is the same as in 861vd.
+ * adc_nids in ALC660vd are (is) the same as in 861vd
+ */
+static const hda_nid_t alc660vd_dac_nids[3] = {
+       /* front, rear, clfe, rear_surr */
+       0x02, 0x04, 0x03
+};
+
+static const hda_nid_t alc861vd_adc_nids[1] = {
+       /* ADC0 */
+       0x09,
+};
+
+static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
+
+/* input MUX */
+/* FIXME: should be a matrix-type input source selection */
+static const struct hda_input_mux alc861vd_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
+static const struct hda_input_mux alc861vd_dallas_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+       },
+};
+
+static const struct hda_input_mux alc861vd_hp_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Front Mic", 0x0 },
+               { "ATAPI Mic", 0x1 },
+       },
+};
+
+/*
+ * 2ch mode
+ */
+static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
+       { 2, NULL }
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc861vd_6stack_ch6_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static const struct hda_verb alc861vd_6stack_ch8_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
+       { 6, alc861vd_6stack_ch6_init },
+       { 8, alc861vd_6stack_ch8_init },
+};
+
+static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
+                               HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
+                               HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+
+       { } /* end */
+};
+
+/* Pin assignment: Speaker=0x14, HP = 0x15,
+ *                 Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
+ */
+static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+/* Pin assignment: Speaker=0x14, Line-out = 0x15,
+ *                 Front Mic=0x18, ATAPI Mic = 0x19,
+ */
+static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+       { } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static const struct hda_verb alc861vd_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
+        * the analog-loopback mixer widget
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+       /*
+        * Set up output mixers (0x02 - 0x05)
+        */
+       /* set vol=0 to output mixers */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {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},
+
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+       { }
+};
+
+/*
+ * 3-stack pin configuration:
+ * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
+ */
+static const struct hda_verb alc861vd_3stack_init_verbs[] = {
+       /*
+        * Set pin mode and muting
+        */
+       /* set front pin widgets 0x14 for output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Mic (rear) pin: input vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin: input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line-2 In: Headphone output (output 0 - 0x0c) */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* CD pin widget for input */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       { }
+};
+
+/*
+ * 6-stack pin configuration:
+ */
+static const struct hda_verb alc861vd_6stack_init_verbs[] = {
+       /*
+        * Set pin mode and muting
+        */
+       /* set front pin widgets 0x14 for output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Rear Pin: output 1 (0x0d) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       /* CLFE Pin: output 2 (0x0e) */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* Side Pin: output 3 (0x0f) */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+
+       /* Mic (rear) pin: input vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin: input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line-2 In: Headphone output (output 0 - 0x0c) */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* CD pin widget for input */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       { }
+};
+
+static const struct hda_verb alc861vd_eapd_verbs[] = {
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+       {}
+};
+
+static void alc861vd_lenovo_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
+{
+       alc_hp_automute(codec);
+       alc88x_simple_mic_automute(codec);
+}
+
+static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
+                                       unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC_MIC_EVENT:
+               alc88x_simple_mic_automute(codec);
+               break;
+       default:
+               alc_sku_unsol_event(codec, res);
+               break;
+       }
+}
+
+static const struct hda_verb alc861vd_dallas_verbs[] = {
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {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},
+
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+
+       { } /* end */
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc861vd_dallas_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+/*
+ * configuration and preset
+ */
+static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
+       [ALC660VD_3ST]          = "3stack-660",
+       [ALC660VD_3ST_DIG]      = "3stack-660-digout",
+       [ALC660VD_ASUS_V1S]     = "asus-v1s",
+       [ALC861VD_3ST]          = "3stack",
+       [ALC861VD_3ST_DIG]      = "3stack-digout",
+       [ALC861VD_6ST_DIG]      = "6stack-digout",
+       [ALC861VD_LENOVO]       = "lenovo",
+       [ALC861VD_DALLAS]       = "dallas",
+       [ALC861VD_HP]           = "hp",
+       [ALC861VD_AUTO]         = "auto",
+};
+
+static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
+       SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
+       SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
+       /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
+       SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
+       SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
+       SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
+       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
+       /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
+       SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
+       SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
+       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
+       SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
+       SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
+       {}
+};
+
+static const struct alc_config_preset alc861vd_presets[] = {
+       [ALC660VD_3ST] = {
+               .mixers = { alc861vd_3st_mixer },
+               .init_verbs = { alc861vd_volume_init_verbs,
+                                alc861vd_3stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+               .dac_nids = alc660vd_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_capture_source,
+       },
+       [ALC660VD_3ST_DIG] = {
+               .mixers = { alc861vd_3st_mixer },
+               .init_verbs = { alc861vd_volume_init_verbs,
+                                alc861vd_3stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+               .dac_nids = alc660vd_dac_nids,
+               .dig_out_nid = ALC861VD_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_capture_source,
+       },
+       [ALC861VD_3ST] = {
+               .mixers = { alc861vd_3st_mixer },
+               .init_verbs = { alc861vd_volume_init_verbs,
+                                alc861vd_3stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+               .dac_nids = alc861vd_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_capture_source,
+       },
+       [ALC861VD_3ST_DIG] = {
+               .mixers = { alc861vd_3st_mixer },
+               .init_verbs = { alc861vd_volume_init_verbs,
+                                alc861vd_3stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+               .dac_nids = alc861vd_dac_nids,
+               .dig_out_nid = ALC861VD_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_capture_source,
+       },
+       [ALC861VD_6ST_DIG] = {
+               .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
+               .init_verbs = { alc861vd_volume_init_verbs,
+                               alc861vd_6stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+               .dac_nids = alc861vd_dac_nids,
+               .dig_out_nid = ALC861VD_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
+               .channel_mode = alc861vd_6stack_modes,
+               .input_mux = &alc861vd_capture_source,
+       },
+       [ALC861VD_LENOVO] = {
+               .mixers = { alc861vd_lenovo_mixer },
+               .init_verbs = { alc861vd_volume_init_verbs,
+                               alc861vd_3stack_init_verbs,
+                               alc861vd_eapd_verbs,
+                               alc861vd_lenovo_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+               .dac_nids = alc660vd_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_capture_source,
+               .unsol_event = alc861vd_lenovo_unsol_event,
+               .setup = alc861vd_lenovo_setup,
+               .init_hook = alc861vd_lenovo_init_hook,
+       },
+       [ALC861VD_DALLAS] = {
+               .mixers = { alc861vd_dallas_mixer },
+               .init_verbs = { alc861vd_dallas_verbs },
+               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+               .dac_nids = alc861vd_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_dallas_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc861vd_dallas_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC861VD_HP] = {
+               .mixers = { alc861vd_hp_mixer },
+               .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
+               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+               .dac_nids = alc861vd_dac_nids,
+               .dig_out_nid = ALC861VD_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_hp_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc861vd_dallas_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC660VD_ASUS_V1S] = {
+               .mixers = { alc861vd_lenovo_mixer },
+               .init_verbs = { alc861vd_volume_init_verbs,
+                               alc861vd_3stack_init_verbs,
+                               alc861vd_eapd_verbs,
+                               alc861vd_lenovo_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+               .dac_nids = alc660vd_dac_nids,
+               .dig_out_nid = ALC861VD_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_capture_source,
+               .unsol_event = alc861vd_lenovo_unsol_event,
+               .setup = alc861vd_lenovo_setup,
+               .init_hook = alc861vd_lenovo_init_hook,
+       },
+};
+
diff --git a/sound/pci/hda/alc880_quirks.c b/sound/pci/hda/alc880_quirks.c
new file mode 100644 (file)
index 0000000..c844d2b
--- /dev/null
@@ -0,0 +1,1898 @@
+/*
+ * ALC880 quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC880 board config type */
+enum {
+       ALC880_AUTO,
+       ALC880_3ST,
+       ALC880_3ST_DIG,
+       ALC880_5ST,
+       ALC880_5ST_DIG,
+       ALC880_W810,
+       ALC880_Z71V,
+       ALC880_6ST,
+       ALC880_6ST_DIG,
+       ALC880_F1734,
+       ALC880_ASUS,
+       ALC880_ASUS_DIG,
+       ALC880_ASUS_W1V,
+       ALC880_ASUS_DIG2,
+       ALC880_FUJITSU,
+       ALC880_UNIWILL_DIG,
+       ALC880_UNIWILL,
+       ALC880_UNIWILL_P53,
+       ALC880_CLEVO,
+       ALC880_TCL_S700,
+       ALC880_LG,
+       ALC880_LG_LW,
+       ALC880_MEDION_RIM,
+#ifdef CONFIG_SND_DEBUG
+       ALC880_TEST,
+#endif
+       ALC880_MODEL_LAST /* last tag */
+};
+
+/*
+ * ALC880 3-stack model
+ *
+ * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
+ * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
+ *                 F-Mic = 0x1b, HP = 0x19
+ */
+
+static const hda_nid_t alc880_dac_nids[4] = {
+       /* front, rear, clfe, rear_surr */
+       0x02, 0x05, 0x04, 0x03
+};
+
+static const hda_nid_t alc880_adc_nids[3] = {
+       /* ADC0-2 */
+       0x07, 0x08, 0x09,
+};
+
+/* The datasheet says the node 0x07 is connected from inputs,
+ * but it shows zero connection in the real implementation on some devices.
+ * Note: this is a 915GAV bug, fixed on 915GLV
+ */
+static const hda_nid_t alc880_adc_nids_alt[2] = {
+       /* ADC1-2 */
+       0x08, 0x09,
+};
+
+#define ALC880_DIGOUT_NID      0x06
+#define ALC880_DIGIN_NID       0x0a
+#define ALC880_PIN_CD_NID      0x1c
+
+static const struct hda_input_mux alc880_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x3 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
+/* channel source setting (2/6 channel selection for 3-stack) */
+/* 2ch mode */
+static const struct hda_verb alc880_threestack_ch2_init[] = {
+       /* set line-in to input, mute it */
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       /* set mic-in to input vref 80%, mute it */
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/* 6ch mode */
+static const struct hda_verb alc880_threestack_ch6_init[] = {
+       /* set line-in to output, unmute it */
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       /* set mic-in to output, unmute it */
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc880_threestack_modes[2] = {
+       { 2, alc880_threestack_ch2_init },
+       { 6, alc880_threestack_ch6_init },
+};
+
+static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+/*
+ * ALC880 5-stack model
+ *
+ * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
+ *      Side = 0x02 (0xd)
+ * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
+ *                 Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
+ */
+
+/* additional mixers to alc880_three_stack_mixer */
+static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
+       { } /* end */
+};
+
+/* channel source setting (6/8 channel selection for 5-stack) */
+/* 6ch mode */
+static const struct hda_verb alc880_fivestack_ch6_init[] = {
+       /* set line-in to input, mute it */
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/* 8ch mode */
+static const struct hda_verb alc880_fivestack_ch8_init[] = {
+       /* set line-in to output, unmute it */
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc880_fivestack_modes[2] = {
+       { 6, alc880_fivestack_ch6_init },
+       { 8, alc880_fivestack_ch8_init },
+};
+
+
+/*
+ * ALC880 6-stack model
+ *
+ * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
+ *      Side = 0x05 (0x0f)
+ * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
+ *   Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
+ */
+
+static const hda_nid_t alc880_6st_dac_nids[4] = {
+       /* front, rear, clfe, rear_surr */
+       0x02, 0x03, 0x04, 0x05
+};
+
+static const struct hda_input_mux alc880_6stack_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
+/* fixed 8-channels */
+static const struct hda_channel_mode alc880_sixstack_modes[1] = {
+       { 8, NULL },
+};
+
+static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+
+/*
+ * ALC880 W810 model
+ *
+ * W810 has rear IO for:
+ * Front (DAC 02)
+ * Surround (DAC 03)
+ * Center/LFE (DAC 04)
+ * Digital out (06)
+ *
+ * The system also has a pair of internal speakers, and a headphone jack.
+ * These are both connected to Line2 on the codec, hence to DAC 02.
+ *
+ * There is a variable resistor to control the speaker or headphone
+ * volume. This is a hardware-only device without a software API.
+ *
+ * Plugging headphones in will disable the internal speakers. This is
+ * implemented in hardware, not via the driver using jack sense. In
+ * a similar fashion, plugging into the rear socket marked "front" will
+ * disable both the speakers and headphones.
+ *
+ * For input, there's a microphone jack, and an "audio in" jack.
+ * These may not do anything useful with this driver yet, because I
+ * haven't setup any initialization verbs for these yet...
+ */
+
+static const hda_nid_t alc880_w810_dac_nids[3] = {
+       /* front, rear/surround, clfe */
+       0x02, 0x03, 0x04
+};
+
+/* fixed 6 channels */
+static const struct hda_channel_mode alc880_w810_modes[1] = {
+       { 6, NULL }
+};
+
+/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
+static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+
+/*
+ * Z710V model
+ *
+ * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
+ * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
+ *                 Line = 0x1a
+ */
+
+static const hda_nid_t alc880_z71v_dac_nids[1] = {
+       0x02
+};
+#define ALC880_Z71V_HP_DAC     0x03
+
+/* fixed 2 channels */
+static const struct hda_channel_mode alc880_2_jack_modes[1] = {
+       { 2, NULL }
+};
+
+static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+
+/*
+ * ALC880 F1734 model
+ *
+ * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
+ * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
+ */
+
+static const hda_nid_t alc880_f1734_dac_nids[1] = {
+       0x03
+};
+#define ALC880_F1734_HP_DAC    0x02
+
+static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_input_mux alc880_f1734_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x1 },
+               { "CD", 0x4 },
+       },
+};
+
+
+/*
+ * ALC880 ASUS model
+ *
+ * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
+ * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
+ *  Mic = 0x18, Line = 0x1a
+ */
+
+#define alc880_asus_dac_nids   alc880_w810_dac_nids    /* identical with w810 */
+#define alc880_asus_modes      alc880_threestack_modes /* 2/6 channel mode */
+
+static const struct snd_kcontrol_new alc880_asus_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+/*
+ * ALC880 ASUS W1V model
+ *
+ * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
+ * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
+ *  Mic = 0x18, Line = 0x1a, Line2 = 0x1b
+ */
+
+/* additional mixers to alc880_asus_mixer */
+static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
+       HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
+       { } /* end */
+};
+
+/* TCL S700 */
+static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+/* Uniwill */
+static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+/*
+ * initialize the codec volumes, etc
+ */
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static const struct hda_verb alc880_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-2 and set the default input to mic-in
+        */
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        * Note: PASD motherboards uses the Line In 2 as the input for front
+        * panel mic (mic 2)
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+
+       /*
+        * Set up output mixers (0x0c - 0x0f)
+        */
+       /* set vol=0 to output mixers */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+       { }
+};
+
+/*
+ * 3-stack pin configuration:
+ * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
+ */
+static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
+       /*
+        * preset connection lists of input pins
+        * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
+        */
+       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+       {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+       {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
+
+       /*
+        * Set pin mode and muting
+        */
+       /* set front pin widgets 0x14 for output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Mic1 (rear panel) pin widget for input and vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Mic2 (as headphone out) for HP output */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Line In pin widget for input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line2 (as front mic) pin widget for input and vref at 80% */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* CD pin widget for input */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       { }
+};
+
+/*
+ * 5-stack pin configuration:
+ * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
+ * line-in/side = 0x1a, f-mic = 0x1b
+ */
+static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
+       /*
+        * preset connection lists of input pins
+        * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
+        */
+       {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+       {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
+
+       /*
+        * Set pin mode and muting
+        */
+       /* set pin widgets 0x14-0x17 for output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       /* unmute pins for output (no gain on this amp) */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Mic1 (rear panel) pin widget for input and vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Mic2 (as headphone out) for HP output */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Line In pin widget for input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line2 (as front mic) pin widget for input and vref at 80% */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* CD pin widget for input */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       { }
+};
+
+/*
+ * W810 pin configuration:
+ * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
+ */
+static const struct hda_verb alc880_pin_w810_init_verbs[] = {
+       /* hphone/speaker input selector: front DAC */
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       { }
+};
+
+/*
+ * Z71V pin configuration:
+ * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
+ */
+static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       { }
+};
+
+/*
+ * 6-stack pin configuration:
+ * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
+ * f-mic = 0x19, line = 0x1a, HP = 0x1b
+ */
+static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       { }
+};
+
+/*
+ * Uniwill pin configuration:
+ * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
+ * line = 0x1a
+ */
+static const struct hda_verb alc880_uniwill_init_verbs[] = {
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
+       /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
+
+       { }
+};
+
+/*
+* Uniwill P53
+* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
+ */
+static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_DCVOL_EVENT},
+
+       { }
+};
+
+static const struct hda_verb alc880_beep_init_verbs[] = {
+       { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
+       { }
+};
+
+static void alc880_uniwill_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x16;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc880_uniwill_init_hook(struct hda_codec *codec)
+{
+       alc_hp_automute(codec);
+       alc88x_simple_mic_automute(codec);
+}
+
+static void alc880_uniwill_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       /* Looks like the unsol event is incompatible with the standard
+        * definition.  4bit tag is placed at 28 bit!
+        */
+       switch (res >> 28) {
+       case ALC_MIC_EVENT:
+               alc88x_simple_mic_automute(codec);
+               break;
+       default:
+               alc_sku_unsol_event(codec, res);
+               break;
+       }
+}
+
+static void alc880_uniwill_p53_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x21, 0,
+                                    AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+       present &= HDA_AMP_VOLMASK;
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
+                                HDA_AMP_VOLMASK, present);
+       snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
+                                HDA_AMP_VOLMASK, present);
+}
+
+static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       /* Looks like the unsol event is incompatible with the standard
+        * definition.  4bit tag is placed at 28 bit!
+        */
+       if ((res >> 28) == ALC_DCVOL_EVENT)
+               alc880_uniwill_p53_dcvol_automute(codec);
+       else
+               alc_sku_unsol_event(codec, res);
+}
+
+/*
+ * F1734 pin configuration:
+ * HP = 0x14, speaker-out = 0x15, mic = 0x18
+ */
+static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
+       {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_DCVOL_EVENT},
+
+       { }
+};
+
+/*
+ * ASUS pin configuration:
+ * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
+ */
+static const struct hda_verb alc880_pin_asus_init_verbs[] = {
+       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
+       {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       { }
+};
+
+/* Enable GPIO mask and set output */
+#define alc880_gpio1_init_verbs        alc_gpio1_init_verbs
+#define alc880_gpio2_init_verbs        alc_gpio2_init_verbs
+#define alc880_gpio3_init_verbs        alc_gpio3_init_verbs
+
+/* Clevo m520g init */
+static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
+       /* headphone output */
+       {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
+       /* line-out */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Line-in */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* CD */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Mic1 (rear panel) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Mic2 (front panel) */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* headphone */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+        /* change to EAPD mode */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x3060},
+
+       { }
+};
+
+static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
+       /* change to EAPD mode */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x3060},
+
+       /* Headphone output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Front output*/
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Line In pin widget for input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       /* CD pin widget for input */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       /* Mic1 (rear panel) pin widget for input and vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+
+       /* change to EAPD mode */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x3070},
+
+       { }
+};
+
+/*
+ * LG m1 express dual
+ *
+ * Pin assignment:
+ *   Rear Line-In/Out (blue): 0x14
+ *   Build-in Mic-In: 0x15
+ *   Speaker-out: 0x17
+ *   HP-Out (green): 0x1b
+ *   Mic-In/Out (red): 0x19
+ *   SPDIF-Out: 0x1e
+ */
+
+/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
+static const hda_nid_t alc880_lg_dac_nids[3] = {
+       0x05, 0x02, 0x03
+};
+
+/* seems analog CD is not working */
+static const struct hda_input_mux alc880_lg_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x1 },
+               { "Line", 0x5 },
+               { "Internal Mic", 0x6 },
+       },
+};
+
+/* 2,4,6 channel modes */
+static const struct hda_verb alc880_lg_ch2_init[] = {
+       /* set line-in and mic-in to input */
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { }
+};
+
+static const struct hda_verb alc880_lg_ch4_init[] = {
+       /* set line-in to out and mic-in to input */
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { }
+};
+
+static const struct hda_verb alc880_lg_ch6_init[] = {
+       /* set line-in and mic-in to output */
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+       { }
+};
+
+static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
+       { 2, alc880_lg_ch2_init },
+       { 4, alc880_lg_ch4_init },
+       { 6, alc880_lg_ch6_init },
+};
+
+static const struct snd_kcontrol_new alc880_lg_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+static const struct hda_verb alc880_lg_init_verbs[] = {
+       /* set capture source to mic-in */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* mute all amp mixer inputs */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+       /* line-in to input */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* built-in mic */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* speaker-out */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* mic-in to input */
+       {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* HP-out */
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* jack sense */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_lg_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x17;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+/*
+ * LG LW20
+ *
+ * Pin assignment:
+ *   Speaker-out: 0x14
+ *   Mic-In: 0x18
+ *   Built-in Mic-In: 0x19
+ *   Line-In: 0x1b
+ *   HP-Out: 0x1a
+ *   SPDIF-Out: 0x1e
+ */
+
+static const struct hda_input_mux alc880_lg_lw_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+               { "Line In", 0x2 },
+       },
+};
+
+#define alc880_lg_lw_modes alc880_threestack_modes
+
+static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+static const struct hda_verb alc880_lg_lw_init_verbs[] = {
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+       {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
+
+       /* set capture source to mic-in */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+       /* speaker-out */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* HP-out */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* mic-in to input */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* built-in mic */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* jack sense */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_lg_lw_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_input_mux alc880_medion_rim_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+       },
+};
+
+static const struct hda_verb alc880_medion_rim_init_verbs[] = {
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Mic1 (rear panel) pin widget for input and vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Mic2 (as headphone out) for HP output */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Internal Speaker */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x3060},
+
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_medion_rim_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       alc_hp_automute(codec);
+       /* toggle EAPD */
+       if (spec->jack_present)
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
+       else
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
+}
+
+static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
+                                         unsigned int res)
+{
+       /* Looks like the unsol event is incompatible with the standard
+        * definition.  4bit tag is placed at 28 bit!
+        */
+       if ((res >> 28) == ALC_HP_EVENT)
+               alc880_medion_rim_automute(codec);
+}
+
+static void alc880_medion_rim_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x1b;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static const struct hda_amp_list alc880_lg_loopbacks[] = {
+       { 0x0b, HDA_INPUT, 1 },
+       { 0x0b, HDA_INPUT, 6 },
+       { 0x0b, HDA_INPUT, 7 },
+       { } /* end */
+};
+#endif
+
+/*
+ * Test configuration for debugging
+ *
+ * Almost all inputs/outputs are enabled.  I/O pins can be configured via
+ * enum controls.
+ */
+#ifdef CONFIG_SND_DEBUG
+static const hda_nid_t alc880_test_dac_nids[4] = {
+       0x02, 0x03, 0x04, 0x05
+};
+
+static const struct hda_input_mux alc880_test_capture_source = {
+       .num_items = 7,
+       .items = {
+               { "In-1", 0x0 },
+               { "In-2", 0x1 },
+               { "In-3", 0x2 },
+               { "In-4", 0x3 },
+               { "CD", 0x4 },
+               { "Front", 0x5 },
+               { "Surround", 0x6 },
+       },
+};
+
+static const struct hda_channel_mode alc880_test_modes[4] = {
+       { 2, NULL },
+       { 4, NULL },
+       { 6, NULL },
+       { 8, NULL },
+};
+
+static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       static const char * const texts[] = {
+               "N/A", "Line Out", "HP Out",
+               "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
+       };
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 8;
+       if (uinfo->value.enumerated.item >= 8)
+               uinfo->value.enumerated.item = 7;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
+       unsigned int pin_ctl, item = 0;
+
+       pin_ctl = snd_hda_codec_read(codec, nid, 0,
+                                    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+       if (pin_ctl & AC_PINCTL_OUT_EN) {
+               if (pin_ctl & AC_PINCTL_HP_EN)
+                       item = 2;
+               else
+                       item = 1;
+       } else if (pin_ctl & AC_PINCTL_IN_EN) {
+               switch (pin_ctl & AC_PINCTL_VREFEN) {
+               case AC_PINCTL_VREF_HIZ: item = 3; break;
+               case AC_PINCTL_VREF_50:  item = 4; break;
+               case AC_PINCTL_VREF_GRD: item = 5; break;
+               case AC_PINCTL_VREF_80:  item = 6; break;
+               case AC_PINCTL_VREF_100: item = 7; break;
+               }
+       }
+       ucontrol->value.enumerated.item[0] = item;
+       return 0;
+}
+
+static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
+       static const unsigned int ctls[] = {
+               0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
+               AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
+               AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
+               AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
+               AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
+               AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
+       };
+       unsigned int old_ctl, new_ctl;
+
+       old_ctl = snd_hda_codec_read(codec, nid, 0,
+                                    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+       new_ctl = ctls[ucontrol->value.enumerated.item[0]];
+       if (old_ctl != new_ctl) {
+               int val;
+               snd_hda_codec_write_cache(codec, nid, 0,
+                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                         new_ctl);
+               val = ucontrol->value.enumerated.item[0] >= 3 ?
+                       HDA_AMP_MUTE : 0;
+               snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, val);
+               return 1;
+       }
+       return 0;
+}
+
+static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       static const char * const texts[] = {
+               "Front", "Surround", "CLFE", "Side"
+       };
+       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;
+}
+
+static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
+       unsigned int sel;
+
+       sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
+       ucontrol->value.enumerated.item[0] = sel & 3;
+       return 0;
+}
+
+static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
+       unsigned int sel;
+
+       sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
+       if (ucontrol->value.enumerated.item[0] != sel) {
+               sel = ucontrol->value.enumerated.item[0] & 3;
+               snd_hda_codec_write_cache(codec, nid, 0,
+                                         AC_VERB_SET_CONNECT_SEL, sel);
+               return 1;
+       }
+       return 0;
+}
+
+#define PIN_CTL_TEST(xname,nid) {                      \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,    \
+                       .name = xname,                 \
+                       .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
+                       .info = alc_test_pin_ctl_info, \
+                       .get = alc_test_pin_ctl_get,   \
+                       .put = alc_test_pin_ctl_put,   \
+                       .private_value = nid           \
+                       }
+
+#define PIN_SRC_TEST(xname,nid) {                      \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,    \
+                       .name = xname,                 \
+                       .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
+                       .info = alc_test_pin_src_info, \
+                       .get = alc_test_pin_src_get,   \
+                       .put = alc_test_pin_src_put,   \
+                       .private_value = nid           \
+                       }
+
+static const struct snd_kcontrol_new alc880_test_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       PIN_CTL_TEST("Front Pin Mode", 0x14),
+       PIN_CTL_TEST("Surround Pin Mode", 0x15),
+       PIN_CTL_TEST("CLFE Pin Mode", 0x16),
+       PIN_CTL_TEST("Side Pin Mode", 0x17),
+       PIN_CTL_TEST("In-1 Pin Mode", 0x18),
+       PIN_CTL_TEST("In-2 Pin Mode", 0x19),
+       PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
+       PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
+       PIN_SRC_TEST("In-1 Pin Source", 0x18),
+       PIN_SRC_TEST("In-2 Pin Source", 0x19),
+       PIN_SRC_TEST("In-3 Pin Source", 0x1a),
+       PIN_SRC_TEST("In-4 Pin Source", 0x1b),
+       HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
+       HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+static const struct hda_verb alc880_test_init_verbs[] = {
+       /* Unmute inputs of 0x0c - 0x0f */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Vol output for 0x0c-0x0f */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* Set output pins 0x14-0x17 */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       /* Unmute output pins 0x14-0x17 */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Set input pins 0x18-0x1c */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       /* Mute input pins 0x18-0x1b */
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* ADC set up */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Analog input/passthru */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       { }
+};
+#endif
+
+/*
+ */
+
+static const char * const alc880_models[ALC880_MODEL_LAST] = {
+       [ALC880_3ST]            = "3stack",
+       [ALC880_TCL_S700]       = "tcl",
+       [ALC880_3ST_DIG]        = "3stack-digout",
+       [ALC880_CLEVO]          = "clevo",
+       [ALC880_5ST]            = "5stack",
+       [ALC880_5ST_DIG]        = "5stack-digout",
+       [ALC880_W810]           = "w810",
+       [ALC880_Z71V]           = "z71v",
+       [ALC880_6ST]            = "6stack",
+       [ALC880_6ST_DIG]        = "6stack-digout",
+       [ALC880_ASUS]           = "asus",
+       [ALC880_ASUS_W1V]       = "asus-w1v",
+       [ALC880_ASUS_DIG]       = "asus-dig",
+       [ALC880_ASUS_DIG2]      = "asus-dig2",
+       [ALC880_UNIWILL_DIG]    = "uniwill",
+       [ALC880_UNIWILL_P53]    = "uniwill-p53",
+       [ALC880_FUJITSU]        = "fujitsu",
+       [ALC880_F1734]          = "F1734",
+       [ALC880_LG]             = "lg",
+       [ALC880_LG_LW]          = "lg-lw",
+       [ALC880_MEDION_RIM]     = "medion",
+#ifdef CONFIG_SND_DEBUG
+       [ALC880_TEST]           = "test",
+#endif
+       [ALC880_AUTO]           = "auto",
+};
+
+static const struct snd_pci_quirk alc880_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
+       SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
+       SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
+       SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
+       SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
+       SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
+       SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
+       SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
+       SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
+       SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
+       /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
+       SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
+       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
+       SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
+       SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
+       SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
+       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
+       SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
+       SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
+       SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
+       SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
+       SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
+       SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
+       SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
+       SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
+       SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
+       SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
+       SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
+       SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
+       SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
+       SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
+       SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
+       SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
+       SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
+       SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
+       SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
+       SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
+       SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
+       SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
+       SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
+       SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
+       SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
+       SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
+       /* default Intel */
+       SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
+       SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
+       {}
+};
+
+/*
+ * ALC880 codec presets
+ */
+static const struct alc_config_preset alc880_presets[] = {
+       [ALC880_3ST] = {
+               .mixers = { alc880_three_stack_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_3stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+               .dac_nids = alc880_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+               .channel_mode = alc880_threestack_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_3ST_DIG] = {
+               .mixers = { alc880_three_stack_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_3stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+               .dac_nids = alc880_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+               .channel_mode = alc880_threestack_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_TCL_S700] = {
+               .mixers = { alc880_tcl_s700_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_tcl_S700_init_verbs,
+                               alc880_gpio2_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+               .dac_nids = alc880_dac_nids,
+               .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
+               .num_adc_nids = 1, /* single ADC */
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+               .channel_mode = alc880_2_jack_modes,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_5ST] = {
+               .mixers = { alc880_three_stack_mixer,
+                           alc880_five_stack_mixer},
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_5stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+               .dac_nids = alc880_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
+               .channel_mode = alc880_fivestack_modes,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_5ST_DIG] = {
+               .mixers = { alc880_three_stack_mixer,
+                           alc880_five_stack_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_5stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+               .dac_nids = alc880_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
+               .channel_mode = alc880_fivestack_modes,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_6ST] = {
+               .mixers = { alc880_six_stack_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_6stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
+               .dac_nids = alc880_6st_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
+               .channel_mode = alc880_sixstack_modes,
+               .input_mux = &alc880_6stack_capture_source,
+       },
+       [ALC880_6ST_DIG] = {
+               .mixers = { alc880_six_stack_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_6stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
+               .dac_nids = alc880_6st_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
+               .channel_mode = alc880_sixstack_modes,
+               .input_mux = &alc880_6stack_capture_source,
+       },
+       [ALC880_W810] = {
+               .mixers = { alc880_w810_base_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_w810_init_verbs,
+                               alc880_gpio2_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
+               .dac_nids = alc880_w810_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
+               .channel_mode = alc880_w810_modes,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_Z71V] = {
+               .mixers = { alc880_z71v_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_z71v_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
+               .dac_nids = alc880_z71v_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+               .channel_mode = alc880_2_jack_modes,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_F1734] = {
+               .mixers = { alc880_f1734_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_f1734_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
+               .dac_nids = alc880_f1734_dac_nids,
+               .hp_nid = 0x02,
+               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+               .channel_mode = alc880_2_jack_modes,
+               .input_mux = &alc880_f1734_capture_source,
+               .unsol_event = alc880_uniwill_p53_unsol_event,
+               .setup = alc880_uniwill_p53_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC880_ASUS] = {
+               .mixers = { alc880_asus_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_asus_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+               .dac_nids = alc880_asus_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+               .channel_mode = alc880_asus_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_ASUS_DIG] = {
+               .mixers = { alc880_asus_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_asus_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+               .dac_nids = alc880_asus_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+               .channel_mode = alc880_asus_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_ASUS_DIG2] = {
+               .mixers = { alc880_asus_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_asus_init_verbs,
+                               alc880_gpio2_init_verbs }, /* use GPIO2 */
+               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+               .dac_nids = alc880_asus_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+               .channel_mode = alc880_asus_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_ASUS_W1V] = {
+               .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_asus_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+               .dac_nids = alc880_asus_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+               .channel_mode = alc880_asus_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_UNIWILL_DIG] = {
+               .mixers = { alc880_asus_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_asus_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+               .dac_nids = alc880_asus_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+               .channel_mode = alc880_asus_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_UNIWILL] = {
+               .mixers = { alc880_uniwill_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_uniwill_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+               .dac_nids = alc880_asus_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+               .channel_mode = alc880_threestack_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_capture_source,
+               .unsol_event = alc880_uniwill_unsol_event,
+               .setup = alc880_uniwill_setup,
+               .init_hook = alc880_uniwill_init_hook,
+       },
+       [ALC880_UNIWILL_P53] = {
+               .mixers = { alc880_uniwill_p53_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_uniwill_p53_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+               .dac_nids = alc880_asus_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
+               .channel_mode = alc880_threestack_modes,
+               .input_mux = &alc880_capture_source,
+               .unsol_event = alc880_uniwill_p53_unsol_event,
+               .setup = alc880_uniwill_p53_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC880_FUJITSU] = {
+               .mixers = { alc880_fujitsu_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_uniwill_p53_init_verbs,
+                               alc880_beep_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+               .dac_nids = alc880_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+               .channel_mode = alc880_2_jack_modes,
+               .input_mux = &alc880_capture_source,
+               .unsol_event = alc880_uniwill_p53_unsol_event,
+               .setup = alc880_uniwill_p53_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC880_CLEVO] = {
+               .mixers = { alc880_three_stack_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_pin_clevo_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+               .dac_nids = alc880_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+               .channel_mode = alc880_threestack_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_capture_source,
+       },
+       [ALC880_LG] = {
+               .mixers = { alc880_lg_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_lg_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
+               .dac_nids = alc880_lg_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
+               .channel_mode = alc880_lg_ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc880_lg_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc880_lg_setup,
+               .init_hook = alc_hp_automute,
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+               .loopbacks = alc880_lg_loopbacks,
+#endif
+       },
+       [ALC880_LG_LW] = {
+               .mixers = { alc880_lg_lw_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_lg_lw_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+               .dac_nids = alc880_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
+               .channel_mode = alc880_lg_lw_modes,
+               .input_mux = &alc880_lg_lw_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc880_lg_lw_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC880_MEDION_RIM] = {
+               .mixers = { alc880_medion_rim_mixer },
+               .init_verbs = { alc880_volume_init_verbs,
+                               alc880_medion_rim_init_verbs,
+                               alc_gpio2_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+               .dac_nids = alc880_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+               .channel_mode = alc880_2_jack_modes,
+               .input_mux = &alc880_medion_rim_capture_source,
+               .unsol_event = alc880_medion_rim_unsol_event,
+               .setup = alc880_medion_rim_setup,
+               .init_hook = alc880_medion_rim_automute,
+       },
+#ifdef CONFIG_SND_DEBUG
+       [ALC880_TEST] = {
+               .mixers = { alc880_test_mixer },
+               .init_verbs = { alc880_test_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
+               .dac_nids = alc880_test_dac_nids,
+               .dig_out_nid = ALC880_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
+               .channel_mode = alc880_test_modes,
+               .input_mux = &alc880_test_capture_source,
+       },
+#endif
+};
+
diff --git a/sound/pci/hda/alc882_quirks.c b/sound/pci/hda/alc882_quirks.c
new file mode 100644 (file)
index 0000000..617d047
--- /dev/null
@@ -0,0 +1,3755 @@
+/*
+ * ALC882/ALC883/ALC888/ALC889 quirk models
+ * included by patch_realtek.c
+ */
+
+/* ALC882 models */
+enum {
+       ALC882_AUTO,
+       ALC882_3ST_DIG,
+       ALC882_6ST_DIG,
+       ALC882_ARIMA,
+       ALC882_W2JC,
+       ALC882_TARGA,
+       ALC882_ASUS_A7J,
+       ALC882_ASUS_A7M,
+       ALC885_MACPRO,
+       ALC885_MBA21,
+       ALC885_MBP3,
+       ALC885_MB5,
+       ALC885_MACMINI3,
+       ALC885_IMAC24,
+       ALC885_IMAC91,
+       ALC883_3ST_2ch_DIG,
+       ALC883_3ST_6ch_DIG,
+       ALC883_3ST_6ch,
+       ALC883_6ST_DIG,
+       ALC883_TARGA_DIG,
+       ALC883_TARGA_2ch_DIG,
+       ALC883_TARGA_8ch_DIG,
+       ALC883_ACER,
+       ALC883_ACER_ASPIRE,
+       ALC888_ACER_ASPIRE_4930G,
+       ALC888_ACER_ASPIRE_6530G,
+       ALC888_ACER_ASPIRE_8930G,
+       ALC888_ACER_ASPIRE_7730G,
+       ALC883_MEDION,
+       ALC883_MEDION_WIM2160,
+       ALC883_LAPTOP_EAPD,
+       ALC883_LENOVO_101E_2ch,
+       ALC883_LENOVO_NB0763,
+       ALC888_LENOVO_MS7195_DIG,
+       ALC888_LENOVO_SKY,
+       ALC883_HAIER_W66,
+       ALC888_3ST_HP,
+       ALC888_6ST_DELL,
+       ALC883_MITAC,
+       ALC883_CLEVO_M540R,
+       ALC883_CLEVO_M720,
+       ALC883_FUJITSU_PI2515,
+       ALC888_FUJITSU_XA3530,
+       ALC883_3ST_6ch_INTEL,
+       ALC889A_INTEL,
+       ALC889_INTEL,
+       ALC888_ASUS_M90V,
+       ALC888_ASUS_EEE1601,
+       ALC889A_MB31,
+       ALC1200_ASUS_P5Q,
+       ALC883_SONY_VAIO_TT,
+       ALC882_MODEL_LAST,
+};
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
+/* Mic-in jack as mic in */
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+/* Line-in jack as Line in */
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+/* Line-Out as Front */
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
+/* Mic-in jack as mic in */
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+/* Line-in jack as Surround */
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-Out as Front */
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
+/* Mic-in jack as CLFE */
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-in jack as Surround */
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+       { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
+/* Mic-in jack as CLFE */
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-in jack as Surround */
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-Out as Side */
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
+       { 2, alc888_4ST_ch2_intel_init },
+       { 4, alc888_4ST_ch4_intel_init },
+       { 6, alc888_4ST_ch6_intel_init },
+       { 8, alc888_4ST_ch8_intel_init },
+};
+
+/*
+ * ALC888 Fujitsu Siemens Amillo xa3530
+ */
+
+static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
+/* Front Mic: set to PIN_IN (empty by default) */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Connect Internal HP to Front */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Connect Bass HP to Front */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Connect Line-Out side jack (SPDIF) to Side */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+/* Connect Mic jack to CLFE */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
+/* Connect Line-in jack to Surround */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+/* Connect HP out jack to Front */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Enable unsolicited event for HP jack and Line-out jack */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {}
+};
+
+static void alc889_automute_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
+       spec->autocfg.speaker_pins[3] = 0x19;
+       spec->autocfg.speaker_pins[4] = 0x1a;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc889_intel_init_hook(struct hda_codec *codec)
+{
+       alc889_coef_init(codec);
+       alc_hp_automute(codec);
+}
+
+static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x17; /* line-out */
+       spec->autocfg.hp_pins[1] = 0x1b; /* hp */
+       spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
+       spec->autocfg.speaker_pins[1] = 0x15; /* bass */
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+/*
+ * ALC888 Acer Aspire 4930G model
+ */
+
+static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
+/* Front Mic: set to PIN_IN (empty by default) */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+/* Connect Internal HP to front */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Connect HP out to front */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+/*
+ * ALC888 Acer Aspire 6530G model
+ */
+
+static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
+/* Route to built-in subwoofer as well as speakers */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+/* Bias voltage on for external mic port */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
+/* Front Mic: set to PIN_IN (empty by default) */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+/* Enable speaker output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/* Enable headphone output */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+/*
+ *ALC888 Acer Aspire 7730G model
+ */
+
+static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
+/* Bias voltage on for external mic port */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
+/* Front Mic: set to PIN_IN (empty by default) */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+/* Enable speaker output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/* Enable headphone output */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/*Enable internal subwoofer */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
+       {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+/*
+ * ALC889 Acer Aspire 8930G model
+ */
+
+static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
+/* Front Mic: set to PIN_IN (empty by default) */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+/* Connect Internal Front to Front */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Connect Internal Rear to Rear */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
+/* Connect Internal CLFE to CLFE */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+/* Connect HP out to Front */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Enable all DACs */
+/*  DAC DISABLE/MUTE 1? */
+/*  setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
+/*  DAC DISABLE/MUTE 2? */
+/*  some bit here disables the other DACs. Init=0x4900 */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
+/* DMIC fix
+ * This laptop has a stereo digital microphone. The mics are only 1cm apart
+ * which makes the stereo useless. However, either the mic or the ALC889
+ * makes the signal become a difference/sum signal instead of standard
+ * stereo, which is annoying. So instead we flip this bit which makes the
+ * codec replicate the sum signal to both channels, turning it into a
+ * normal mono mic.
+ */
+/*  DMIC_CONTROL? Init value = 0x0001 */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
+       { }
+};
+
+static const struct hda_input_mux alc888_2_capture_sources[2] = {
+       /* Front mic only available on one ADC */
+       {
+               .num_items = 4,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+                       { "Front Mic", 0xb },
+               },
+       },
+       {
+               .num_items = 3,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+               },
+       }
+};
+
+static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
+       /* Interal mic only available on one ADC */
+       {
+               .num_items = 5,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line In", 0x2 },
+                       { "CD", 0x4 },
+                       { "Input Mix", 0xa },
+                       { "Internal Mic", 0xb },
+               },
+       },
+       {
+               .num_items = 4,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line In", 0x2 },
+                       { "CD", 0x4 },
+                       { "Input Mix", 0xa },
+               },
+       }
+};
+
+static const struct hda_input_mux alc889_capture_sources[3] = {
+       /* Digital mic only available on first "ADC" */
+       {
+               .num_items = 5,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+                       { "Front Mic", 0xb },
+                       { "Input Mix", 0xa },
+               },
+       },
+       {
+               .num_items = 4,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+                       { "Input Mix", 0xa },
+               },
+       },
+       {
+               .num_items = 4,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+                       { "Input Mix", 0xa },
+               },
+       }
+};
+
+static const struct snd_kcontrol_new alc888_base_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+               HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+               HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+               HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+
+static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x1b;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+#define ALC882_DIGOUT_NID      0x06
+#define ALC882_DIGIN_NID       0x0a
+#define ALC883_DIGOUT_NID      ALC882_DIGOUT_NID
+#define ALC883_DIGIN_NID       ALC882_DIGIN_NID
+#define ALC1200_DIGOUT_NID     0x10
+
+
+static const struct hda_channel_mode alc882_ch_modes[1] = {
+       { 8, NULL }
+};
+
+/* DACs */
+static const hda_nid_t alc882_dac_nids[4] = {
+       /* front, rear, clfe, rear_surr */
+       0x02, 0x03, 0x04, 0x05
+};
+#define alc883_dac_nids                alc882_dac_nids
+
+/* ADCs */
+#define alc882_adc_nids                alc880_adc_nids
+#define alc882_adc_nids_alt    alc880_adc_nids_alt
+#define alc883_adc_nids                alc882_adc_nids_alt
+static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
+static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
+#define alc889_adc_nids                alc880_adc_nids
+
+static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
+static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
+#define alc883_capsrc_nids     alc882_capsrc_nids_alt
+static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
+#define alc889_capsrc_nids     alc882_capsrc_nids
+
+/* input MUX */
+/* FIXME: should be a matrix-type input source selection */
+
+static const struct hda_input_mux alc882_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
+#define alc883_capture_source  alc882_capture_source
+
+static const struct hda_input_mux alc889_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Front Mic", 0x0 },
+               { "Mic", 0x3 },
+               { "Line", 0x2 },
+       },
+};
+
+static const struct hda_input_mux mb5_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x1 },
+               { "Line", 0x7 },
+               { "CD", 0x4 },
+       },
+};
+
+static const struct hda_input_mux macmini3_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
+static const struct hda_input_mux alc883_3stack_6ch_intel = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x1 },
+               { "Front Mic", 0x0 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
+static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x1 },
+               { "Line", 0x2 },
+       },
+};
+
+static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
+static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+       },
+};
+
+static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x4 },
+       },
+};
+
+static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x0 },
+               { "Line", 0x2 },
+       },
+};
+
+static const struct hda_input_mux alc889A_mb31_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x0 },
+               /* Front Mic (0x01) unused */
+               { "Line", 0x2 },
+               /* Line 2 (0x03) unused */
+               /* CD (0x04) unused? */
+       },
+};
+
+static const struct hda_input_mux alc889A_imac91_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x01 },
+               { "Line", 0x2 }, /* Not sure! */
+       },
+};
+
+/*
+ * 2ch mode
+ */
+static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
+       { 2, NULL }
+};
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc882_3ST_ch2_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static const struct hda_verb alc882_3ST_ch4_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc882_3ST_ch6_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
+       { 2, alc882_3ST_ch2_init },
+       { 4, alc882_3ST_ch4_init },
+       { 6, alc882_3ST_ch6_init },
+};
+
+#define alc883_3ST_6ch_modes   alc882_3ST_6ch_modes
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
+       { 2, alc883_3ST_ch2_clevo_init },
+       { 4, alc883_3ST_ch4_clevo_init },
+       { 6, alc883_3ST_ch6_clevo_init },
+};
+
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc882_sixstack_ch6_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static const struct hda_verb alc882_sixstack_ch8_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc882_sixstack_modes[2] = {
+       { 6, alc882_sixstack_ch6_init },
+       { 8, alc882_sixstack_ch8_init },
+};
+
+
+/* Macbook Air 2,1 */
+
+static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
+      { 2, NULL },
+};
+
+/*
+ * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
+ */
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc885_mbp_ch2_init[] = {
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static const struct hda_verb alc885_mbp_ch4_init[] = {
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
+       { 2, alc885_mbp_ch2_init },
+       { 4, alc885_mbp_ch4_init },
+};
+
+/*
+ * 2ch
+ * Speakers/Woofer/HP = Front
+ * LineIn = Input
+ */
+static const struct hda_verb alc885_mb5_ch2_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ * Speakers/HP = Front
+ * Woofer = LFE
+ * LineIn = Surround
+ */
+static const struct hda_verb alc885_mb5_ch6_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
+       { 2, alc885_mb5_ch2_init },
+       { 6, alc885_mb5_ch6_init },
+};
+
+#define alc885_macmini3_6ch_modes      alc885_mb5_6ch_modes
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc883_4ST_ch2_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static const struct hda_verb alc883_4ST_ch4_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc883_4ST_ch6_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static const struct hda_verb alc883_4ST_ch8_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
+       { 2, alc883_4ST_ch2_init },
+       { 4, alc883_4ST_ch4_init },
+       { 6, alc883_4ST_ch6_init },
+       { 8, alc883_4ST_ch8_init },
+};
+
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
+       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
+       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
+       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
+       { 2, alc883_3ST_ch2_intel_init },
+       { 4, alc883_3ST_ch4_intel_init },
+       { 6, alc883_3ST_ch6_intel_init },
+};
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc889_ch2_intel_init[] = {
+       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc889_ch6_intel_init[] = {
+       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static const struct hda_verb alc889_ch8_intel_init[] = {
+       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
+       { 2, alc889_ch2_intel_init },
+       { 6, alc889_ch6_intel_init },
+       { 8, alc889_ch8_intel_init },
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc883_sixstack_ch6_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static const struct hda_verb alc883_sixstack_ch8_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc883_sixstack_modes[2] = {
+       { 6, alc883_sixstack_ch6_init },
+       { 8, alc883_sixstack_ch8_init },
+};
+
+
+/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+static const struct snd_kcontrol_new alc882_base_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+/* Macbook Air 2,1 same control for HP and internal Speaker */
+
+static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
+      HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+      HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
+     { }
+};
+
+
+static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       { } /* end */
+};
+
+
+static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc882_targa_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
+ *                 Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
+ */
+static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+static const struct hda_verb alc882_base_init_verbs[] = {
+       /* Front mixer: unmute input/output amp left and right (volume = 0) */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Rear mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* CLFE mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Side mixer */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+       /* Front Pin: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Rear Pin: output 1 (0x0d) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       /* CLFE Pin: output 2 (0x0e) */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* Side Pin: output 3 (0x0f) */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+       /* Mic (rear) pin: input vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin: input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line-2 In: Headphone output (output 0 - 0x0c) */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* CD pin widget for input */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* ADC2: mute amp left and right */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* ADC3: mute amp left and right */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       { }
+};
+
+static const struct hda_verb alc882_adc1_init_verbs[] = {
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* ADC1: mute amp left and right */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       { }
+};
+
+static const struct hda_verb alc882_eapd_verbs[] = {
+       /* change to EAPD mode */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
+       { }
+};
+
+static const struct hda_verb alc889_eapd_verbs[] = {
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+static const struct hda_verb alc_hp15_unsol_verbs[] = {
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {}
+};
+
+static const struct hda_verb alc885_init_verbs[] = {
+       /* Front mixer: unmute input/output amp left and right (volume = 0) */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Rear mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* CLFE mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Side mixer */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* Front HP Pin: output 0 (0x0c) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Front Pin: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Rear Pin: output 1 (0x0d) */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
+       /* CLFE Pin: output 2 (0x0e) */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* Side Pin: output 3 (0x0f) */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+       /* Mic (rear) pin: input vref at 80% */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin: input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       /* Mixer elements: 0x18, , 0x1a, 0x1b */
+       /* Input mixer1 */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* ADC2: mute amp left and right */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* ADC3: mute amp left and right */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+       { }
+};
+
+static const struct hda_verb alc885_init_input_verbs[] = {
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       { }
+};
+
+
+/* Unmute Selector 24h and set the default input to front mic */
+static const struct hda_verb alc889_init_input_verbs[] = {
+       {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       { }
+};
+
+
+#define alc883_init_verbs      alc882_base_init_verbs
+
+/* Mac Pro test */
+static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       /* FIXME: this looks suspicious...
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       */
+       { } /* end */
+};
+
+static const struct hda_verb alc882_macpro_init_verbs[] = {
+       /* Front mixer: unmute input/output amp left and right (volume = 0) */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Front Pin: output 0 (0x0c) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Speaker:  output */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
+       /* Headphone output (output 0 - 0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* ADC1: mute amp left and right */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* ADC2: mute amp left and right */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* ADC3: mute amp left and right */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       { }
+};
+
+/* Macbook 5,1 */
+static const struct hda_verb alc885_mb5_init_verbs[] = {
+       /* DACs */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Front mixer */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Surround mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* LFE mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* HP mixer */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Front Pin (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* LFE Pin (0x0e) */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* HP Pin (0x0f) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
+       { }
+};
+
+/* Macmini 3,1 */
+static const struct hda_verb alc885_macmini3_init_verbs[] = {
+       /* DACs */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Front mixer */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Surround mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* LFE mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* HP mixer */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Front Pin (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* LFE Pin (0x0e) */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* HP Pin (0x0f) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       /* Line In pin */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       { }
+};
+
+
+static const struct hda_verb alc885_mba21_init_verbs[] = {
+       /*Internal and HP Speaker Mixer*/
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /*Internal Speaker Pin (0x0c)*/
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP Pin: output 0 (0x0e) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)},
+       /* Line in (is hp when jack connected)*/
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       { }
+ };
+
+
+/* Macbook Pro rev3 */
+static const struct hda_verb alc885_mbp3_init_verbs[] = {
+       /* Front mixer: unmute input/output amp left and right (volume = 0) */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Rear mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* HP mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Front Pin: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP Pin: output 0 (0x0e) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       /* Mic (rear) pin: input vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin: use output 1 when in LineOut mode */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* ADC1: mute amp left and right */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* ADC2: mute amp left and right */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* ADC3: mute amp left and right */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       { }
+};
+
+/* iMac 9,1 */
+static const struct hda_verb alc885_imac91_init_verbs[] = {
+       /* Internal Speaker Pin (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP Pin: Rear */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)},
+       /* Line in Rear */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Rear mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       { }
+};
+
+/* iMac 24 mixer. */
+static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
+       { } /* end */
+};
+
+/* iMac 24 init verbs. */
+static const struct hda_verb alc885_imac24_init_verbs[] = {
+       /* Internal speakers: output 0 (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Internal speakers: output 0 (0x0c) */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Headphone: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       /* Front Mic: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       { }
+};
+
+/* Toggle speaker-output according to the hp-jack state */
+static void alc885_imac24_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x18;
+       spec->autocfg.speaker_pins[1] = 0x1a;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+#define alc885_mb5_setup       alc885_imac24_setup
+#define alc885_macmini3_setup  alc885_imac24_setup
+
+/* Macbook Air 2,1 */
+static void alc885_mba21_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x18;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+
+
+static void alc885_mbp3_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc885_imac91_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x18;
+       spec->autocfg.speaker_pins[1] = 0x1a;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static const struct hda_verb alc882_targa_verbs[] = {
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc882_targa_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       alc_hp_automute(codec);
+       snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
+                                 spec->jack_present ? 1 : 3);
+}
+
+static void alc882_targa_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x1b;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       if ((res >> 26) == ALC_HP_EVENT)
+               alc882_targa_automute(codec);
+}
+
+static const struct hda_verb alc882_asus_a7j_verbs[] = {
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
+
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+       { } /* end */
+};
+
+static const struct hda_verb alc882_asus_a7m_verbs[] = {
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
+
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+       { } /* end */
+};
+
+static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
+{
+       unsigned int gpiostate, gpiomask, gpiodir;
+
+       gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+                                      AC_VERB_GET_GPIO_DATA, 0);
+
+       if (!muted)
+               gpiostate |= (1 << pin);
+       else
+               gpiostate &= ~(1 << pin);
+
+       gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+                                     AC_VERB_GET_GPIO_MASK, 0);
+       gpiomask |= (1 << pin);
+
+       gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+                                    AC_VERB_GET_GPIO_DIRECTION, 0);
+       gpiodir |= (1 << pin);
+
+
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_MASK, gpiomask);
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DIRECTION, gpiodir);
+
+       msleep(1);
+
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DATA, gpiostate);
+}
+
+/* set up GPIO at initialization */
+static void alc885_macpro_init_hook(struct hda_codec *codec)
+{
+       alc882_gpio_mute(codec, 0, 0);
+       alc882_gpio_mute(codec, 1, 0);
+}
+
+/* set up GPIO and update auto-muting at initialization */
+static void alc885_imac24_init_hook(struct hda_codec *codec)
+{
+       alc885_macpro_init_hook(codec);
+       alc_hp_automute(codec);
+}
+
+/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
+static const struct hda_verb alc889A_mb31_ch2_init[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Line off */
+       { } /* end */
+};
+
+/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
+static const struct hda_verb alc889A_mb31_ch4_init[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
+       { } /* end */
+};
+
+/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
+static const struct hda_verb alc889A_mb31_ch5_init[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as rear */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Line off */
+       { } /* end */
+};
+
+/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
+static const struct hda_verb alc889A_mb31_ch6_init[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as front */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Subwoofer off */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
+       { 2, alc889A_mb31_ch2_init },
+       { 4, alc889A_mb31_ch4_init },
+       { 5, alc889A_mb31_ch5_init },
+       { 6, alc889A_mb31_ch6_init },
+};
+
+static const struct hda_verb alc883_medion_eapd_verbs[] = {
+        /* eanable EAPD on medion laptop */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
+       { }
+};
+
+#define alc883_base_mixer      alc882_base_mixer
+
+static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+                             HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+                             HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_targa_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_verb alc883_medion_wim2160_verbs[] = {
+       /* Unmute front mixer */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* Set speaker pin to front mixer */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Init headphone pin */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+
+       { } /* end */
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_medion_wim2160_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1a;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume",
+                                               0x0d, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
+       /* Output mixers */
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
+               HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
+       /* Output switches */
+       HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
+       /* Boost mixers */
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
+       /* Input mixers */
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct hda_bind_ctls alc883_bind_cap_vol = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+               0
+       },
+};
+
+static const struct hda_bind_ctls alc883_bind_cap_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+               0
+       },
+};
+
+static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
+       HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
+       HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = alc_mux_enum_info,
+               .get = alc_mux_enum_get,
+               .put = alc_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_mitac_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x17;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static const struct hda_verb alc883_mitac_verbs[] = {
+       /* HP */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Subwoofer */
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       /* enable unsolicited event */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, */
+
+       { } /* end */
+};
+
+static const struct hda_verb alc883_clevo_m540r_verbs[] = {
+       /* HP */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Int speaker */
+       /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
+
+       /* enable unsolicited event */
+       /*
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
+       */
+
+       { } /* end */
+};
+
+static const struct hda_verb alc883_clevo_m720_verbs[] = {
+       /* HP */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Int speaker */
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       /* enable unsolicited event */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
+
+       { } /* end */
+};
+
+static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
+       /* HP */
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Subwoofer */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       /* enable unsolicited event */
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+
+       { } /* end */
+};
+
+static const struct hda_verb alc883_targa_verbs[] = {
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+/* Connect Line-Out side jack (SPDIF) to Side */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+/* Connect Mic jack to CLFE */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
+/* Connect Line-in jack to Surround */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+/* Connect HP out jack to Front */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+
+       { } /* end */
+};
+
+static const struct hda_verb alc883_lenovo_101e_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_FRONT_EVENT|AC_USRSP_EN},
+        {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT|AC_USRSP_EN},
+       { } /* end */
+};
+
+static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
+        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       { } /* end */
+};
+
+static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_FRONT_EVENT | AC_USRSP_EN},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT    | AC_USRSP_EN},
+       { } /* end */
+};
+
+static const struct hda_verb alc883_haier_w66_verbs[] = {
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       { } /* end */
+};
+
+static const struct hda_verb alc888_lenovo_sky_verbs[] = {
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
+static const struct hda_verb alc888_6st_dell_verbs[] = {
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
+static const struct hda_verb alc883_vaiott_verbs[] = {
+       /* HP */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+
+       /* enable unsolicited event */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+
+       { } /* end */
+};
+
+static void alc888_3st_hp_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x18;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static const struct hda_verb alc888_3st_hp_verbs[] = {
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Rear : output 1 (0x0d) */
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},  /* CLFE : output 2 (0x0e) */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
+/*
+ * 2ch mode
+ */
+static const struct hda_verb alc888_3st_hp_2ch_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static const struct hda_verb alc888_3st_hp_4ch_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static const struct hda_verb alc888_3st_hp_6ch_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
+       { 2, alc888_3st_hp_2ch_init },
+       { 4, alc888_3st_hp_4ch_init },
+       { 6, alc888_3st_hp_6ch_init },
+};
+
+static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.line_out_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+/* toggle speaker-output according to the hp-jack state */
+#define alc883_targa_init_hook         alc882_targa_init_hook
+#define alc883_targa_unsol_event       alc882_targa_unsol_event
+
+static void alc883_clevo_m720_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
+{
+       alc_hp_automute(codec);
+       alc88x_simple_mic_automute(codec);
+}
+
+static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC_MIC_EVENT:
+               alc88x_simple_mic_automute(codec);
+               break;
+       default:
+               alc_sku_unsol_event(codec, res);
+               break;
+       }
+}
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc883_haier_w66_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc883_lenovo_101e_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.line_out_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->automute = 1;
+       spec->detect_line = 1;
+       spec->automute_lines = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_acer_aspire_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static const struct hda_verb alc883_acer_eapd_verbs[] = {
+       /* HP Pin: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Front Pin: output 0 (0x0c) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
+        /* eanable EAPD on medion laptop */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
+       /* enable unsolicited event */
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
+static void alc888_6st_dell_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x15;
+       spec->autocfg.speaker_pins[2] = 0x16;
+       spec->autocfg.speaker_pins[3] = 0x17;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc888_lenovo_sky_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x15;
+       spec->autocfg.speaker_pins[2] = 0x16;
+       spec->autocfg.speaker_pins[3] = 0x17;
+       spec->autocfg.speaker_pins[4] = 0x1a;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static void alc883_vaiott_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x17;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static const struct hda_verb alc888_asus_m90v_verbs[] = {
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* enable unsolicited event */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
+static void alc883_mode2_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x15;
+       spec->autocfg.speaker_pins[2] = 0x16;
+       spec->ext_mic_pin = 0x18;
+       spec->int_mic_pin = 0x19;
+       spec->auto_mic = 1;
+       spec->automute = 1;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
+}
+
+static const struct hda_verb alc888_asus_eee1601_verbs[] = {
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x0838},
+       /* enable unsolicited event */
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
+static void alc883_eee1601_inithook(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x1b;
+       alc_hp_automute(codec);
+}
+
+static const struct hda_verb alc889A_mb31_verbs[] = {
+       /* Init rear pin (used as headphone output) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},    /* Apple Headphones */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},           /* Connect to front */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+       /* Init line pin (used as output in 4ch and 6ch mode) */
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},           /* Connect to CLFE */
+       /* Init line 2 pin (used as headphone out by default) */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},  /* Use as input */
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
+       { } /* end */
+};
+
+/* Mute speakers according to the headphone jack state */
+static void alc889A_mb31_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       /* Mute only in 2ch or 4ch mode */
+       if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
+           == 0x00) {
+               present = snd_hda_jack_detect(codec, 0x15);
+               snd_hda_codec_amp_stereo(codec, 0x14,  HDA_OUTPUT, 0,
+                       HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+               snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+                       HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       }
+}
+
+static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       if ((res >> 26) == ALC_HP_EVENT)
+               alc889A_mb31_automute(codec);
+}
+
+static const hda_nid_t alc883_slave_dig_outs[] = {
+       ALC1200_DIGOUT_NID, 0,
+};
+
+static const hda_nid_t alc1200_slave_dig_outs[] = {
+       ALC883_DIGOUT_NID, 0,
+};
+
+/*
+ * configuration and preset
+ */
+static const char * const alc882_models[ALC882_MODEL_LAST] = {
+       [ALC882_3ST_DIG]        = "3stack-dig",
+       [ALC882_6ST_DIG]        = "6stack-dig",
+       [ALC882_ARIMA]          = "arima",
+       [ALC882_W2JC]           = "w2jc",
+       [ALC882_TARGA]          = "targa",
+       [ALC882_ASUS_A7J]       = "asus-a7j",
+       [ALC882_ASUS_A7M]       = "asus-a7m",
+       [ALC885_MACPRO]         = "macpro",
+       [ALC885_MB5]            = "mb5",
+       [ALC885_MACMINI3]       = "macmini3",
+       [ALC885_MBA21]          = "mba21",
+       [ALC885_MBP3]           = "mbp3",
+       [ALC885_IMAC24]         = "imac24",
+       [ALC885_IMAC91]         = "imac91",
+       [ALC883_3ST_2ch_DIG]    = "3stack-2ch-dig",
+       [ALC883_3ST_6ch_DIG]    = "3stack-6ch-dig",
+       [ALC883_3ST_6ch]        = "3stack-6ch",
+       [ALC883_6ST_DIG]        = "alc883-6stack-dig",
+       [ALC883_TARGA_DIG]      = "targa-dig",
+       [ALC883_TARGA_2ch_DIG]  = "targa-2ch-dig",
+       [ALC883_TARGA_8ch_DIG]  = "targa-8ch-dig",
+       [ALC883_ACER]           = "acer",
+       [ALC883_ACER_ASPIRE]    = "acer-aspire",
+       [ALC888_ACER_ASPIRE_4930G]      = "acer-aspire-4930g",
+       [ALC888_ACER_ASPIRE_6530G]      = "acer-aspire-6530g",
+       [ALC888_ACER_ASPIRE_8930G]      = "acer-aspire-8930g",
+       [ALC888_ACER_ASPIRE_7730G]      = "acer-aspire-7730g",
+       [ALC883_MEDION]         = "medion",
+       [ALC883_MEDION_WIM2160] = "medion-wim2160",
+       [ALC883_LAPTOP_EAPD]    = "laptop-eapd",
+       [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
+       [ALC883_LENOVO_NB0763]  = "lenovo-nb0763",
+       [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
+       [ALC888_LENOVO_SKY] = "lenovo-sky",
+       [ALC883_HAIER_W66]      = "haier-w66",
+       [ALC888_3ST_HP]         = "3stack-hp",
+       [ALC888_6ST_DELL]       = "6stack-dell",
+       [ALC883_MITAC]          = "mitac",
+       [ALC883_CLEVO_M540R]    = "clevo-m540r",
+       [ALC883_CLEVO_M720]     = "clevo-m720",
+       [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
+       [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
+       [ALC883_3ST_6ch_INTEL]  = "3stack-6ch-intel",
+       [ALC889A_INTEL]         = "intel-alc889a",
+       [ALC889_INTEL]          = "intel-x58",
+       [ALC1200_ASUS_P5Q]      = "asus-p5q",
+       [ALC889A_MB31]          = "mb31",
+       [ALC883_SONY_VAIO_TT]   = "sony-vaio-tt",
+       [ALC882_AUTO]           = "auto",
+};
+
+static const struct snd_pci_quirk alc882_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
+
+       SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
+               ALC888_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
+               ALC888_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
+               ALC888_ACER_ASPIRE_8930G),
+       SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
+               ALC888_ACER_ASPIRE_8930G),
+       SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
+       SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
+       SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
+               ALC888_ACER_ASPIRE_6530G),
+       SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
+               ALC888_ACER_ASPIRE_6530G),
+       SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
+               ALC888_ACER_ASPIRE_7730G),
+       /* default Acer -- disabled as it causes more problems.
+        *    model=auto should work fine now
+        */
+       /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
+
+       SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
+
+       SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
+
+       SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
+       SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
+       SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
+       SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
+       SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
+       SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
+       SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
+       SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
+       SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
+
+       SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
+       SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+       SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
+       SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
+       SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+       SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
+       SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
+       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
+
+       SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
+       SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
+       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
+
+       SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
+       SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
+       SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
+       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
+       SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
+       /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
+       SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
+       SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
+                     ALC883_FUJITSU_PI2515),
+       SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
+               ALC888_FUJITSU_XA3530),
+       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
+       SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+       SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+       SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+       SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
+       SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
+       SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
+
+       SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
+       SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
+       SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
+       SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
+       SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
+       SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
+       SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
+
+       {}
+};
+
+/* codec SSID table for Intel Mac */
+static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
+       SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
+       SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
+       SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
+       SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
+       SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
+       SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
+       SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
+       SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
+       SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
+       SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
+       SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
+       SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
+       SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
+       SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
+       SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
+       SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
+       /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
+        * so apparently no perfect solution yet
+        */
+       SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
+       SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
+       SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
+       {} /* terminator */
+};
+
+static const struct alc_config_preset alc882_presets[] = {
+       [ALC882_3ST_DIG] = {
+               .mixers = { alc882_base_mixer },
+               .init_verbs = { alc882_base_init_verbs,
+                               alc882_adc1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+               .channel_mode = alc882_ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc882_capture_source,
+       },
+       [ALC882_6ST_DIG] = {
+               .mixers = { alc882_base_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc882_base_init_verbs,
+                               alc882_adc1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
+               .channel_mode = alc882_sixstack_modes,
+               .input_mux = &alc882_capture_source,
+       },
+       [ALC882_ARIMA] = {
+               .mixers = { alc882_base_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc882_eapd_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
+               .channel_mode = alc882_sixstack_modes,
+               .input_mux = &alc882_capture_source,
+       },
+       [ALC882_W2JC] = {
+               .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc882_eapd_verbs, alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+               .channel_mode = alc880_threestack_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc882_capture_source,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+       },
+          [ALC885_MBA21] = {
+                       .mixers = { alc885_mba21_mixer },
+                       .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
+                       .num_dacs = 2,
+                       .dac_nids = alc882_dac_nids,
+                       .channel_mode = alc885_mba21_ch_modes,
+                       .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
+                       .input_mux = &alc882_capture_source,
+                       .unsol_event = alc_sku_unsol_event,
+                       .setup = alc885_mba21_setup,
+                       .init_hook = alc_hp_automute,
+       },
+       [ALC885_MBP3] = {
+               .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc885_mbp3_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = 2,
+               .dac_nids = alc882_dac_nids,
+               .hp_nid = 0x04,
+               .channel_mode = alc885_mbp_4ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
+               .input_mux = &alc882_capture_source,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc885_mbp3_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC885_MB5] = {
+               .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc885_mb5_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .channel_mode = alc885_mb5_6ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
+               .input_mux = &mb5_capture_source,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc885_mb5_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC885_MACMINI3] = {
+               .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc885_macmini3_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .channel_mode = alc885_macmini3_6ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
+               .input_mux = &macmini3_capture_source,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc885_macmini3_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC885_MACPRO] = {
+               .mixers = { alc882_macpro_mixer },
+               .init_verbs = { alc882_macpro_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+               .channel_mode = alc882_ch_modes,
+               .input_mux = &alc882_capture_source,
+               .init_hook = alc885_macpro_init_hook,
+       },
+       [ALC885_IMAC24] = {
+               .mixers = { alc885_imac24_mixer },
+               .init_verbs = { alc885_imac24_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+               .channel_mode = alc882_ch_modes,
+               .input_mux = &alc882_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc885_imac24_setup,
+               .init_hook = alc885_imac24_init_hook,
+       },
+       [ALC885_IMAC91] = {
+               .mixers = {alc885_imac91_mixer},
+               .init_verbs = { alc885_imac91_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .channel_mode = alc885_mba21_ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
+               .input_mux = &alc889A_imac91_capture_source,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc885_imac91_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC882_TARGA] = {
+               .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc880_gpio3_init_verbs, alc882_targa_verbs},
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
+               .adc_nids = alc882_adc_nids,
+               .capsrc_nids = alc882_capsrc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
+               .channel_mode = alc882_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc882_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc882_targa_setup,
+               .init_hook = alc882_targa_automute,
+       },
+       [ALC882_ASUS_A7J] = {
+               .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc882_asus_a7j_verbs},
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
+               .adc_nids = alc882_adc_nids,
+               .capsrc_nids = alc882_capsrc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
+               .channel_mode = alc882_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc882_capture_source,
+       },
+       [ALC882_ASUS_A7M] = {
+               .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc882_eapd_verbs, alc880_gpio1_init_verbs,
+                               alc882_asus_a7m_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+               .channel_mode = alc880_threestack_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc882_capture_source,
+       },
+       [ALC883_3ST_2ch_DIG] = {
+               .mixers = { alc883_3ST_2ch_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC883_3ST_6ch_DIG] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC883_3ST_6ch] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC883_3ST_6ch_INTEL] = {
+               .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .slave_dig_outs = alc883_slave_dig_outs,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
+               .channel_mode = alc883_3ST_6ch_intel_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_3stack_6ch_intel,
+       },
+       [ALC889A_INTEL] = {
+               .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
+                               alc_hp15_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
+               .adc_nids = alc889_adc_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .slave_dig_outs = alc883_slave_dig_outs,
+               .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
+               .channel_mode = alc889_8ch_intel_modes,
+               .capsrc_nids = alc889_capsrc_nids,
+               .input_mux = &alc889_capture_source,
+               .setup = alc889_automute_setup,
+               .init_hook = alc_hp_automute,
+               .unsol_event = alc_sku_unsol_event,
+               .need_dac_fix = 1,
+       },
+       [ALC889_INTEL] = {
+               .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
+                               alc889_eapd_verbs, alc_hp15_unsol_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
+               .adc_nids = alc889_adc_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .slave_dig_outs = alc883_slave_dig_outs,
+               .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
+               .channel_mode = alc889_8ch_intel_modes,
+               .capsrc_nids = alc889_capsrc_nids,
+               .input_mux = &alc889_capture_source,
+               .setup = alc889_automute_setup,
+               .init_hook = alc889_intel_init_hook,
+               .unsol_event = alc_sku_unsol_event,
+               .need_dac_fix = 1,
+       },
+       [ALC883_6ST_DIG] = {
+               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC883_TARGA_DIG] = {
+               .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_targa_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc883_targa_unsol_event,
+               .setup = alc882_targa_setup,
+               .init_hook = alc882_targa_automute,
+       },
+       [ALC883_TARGA_2ch_DIG] = {
+               .mixers = { alc883_targa_2ch_mixer},
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_targa_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .adc_nids = alc883_adc_nids_alt,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
+               .capsrc_nids = alc883_capsrc_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc883_targa_unsol_event,
+               .setup = alc882_targa_setup,
+               .init_hook = alc882_targa_automute,
+       },
+       [ALC883_TARGA_8ch_DIG] = {
+               .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
+                           alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_targa_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+               .adc_nids = alc883_adc_nids_rev,
+               .capsrc_nids = alc883_capsrc_nids_rev,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
+               .channel_mode = alc883_4ST_8ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc883_targa_unsol_event,
+               .setup = alc882_targa_setup,
+               .init_hook = alc882_targa_automute,
+       },
+       [ALC883_ACER] = {
+               .mixers = { alc883_base_mixer },
+               /* On TravelMate laptops, GPIO 0 enables the internal speaker
+                * and the headphone jack.  Turn this on and rely on the
+                * standard mute methods whenever the user wants to turn
+                * these outputs off.
+                */
+               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC883_ACER_ASPIRE] = {
+               .mixers = { alc883_acer_aspire_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc883_acer_aspire_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC888_ACER_ASPIRE_4930G] = {
+               .mixers = { alc888_acer_aspire_4930g_mixer,
+                               alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+                               alc888_acer_aspire_4930g_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+               .adc_nids = alc883_adc_nids_rev,
+               .capsrc_nids = alc883_capsrc_nids_rev,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .const_channel_count = 6,
+               .num_mux_defs =
+                       ARRAY_SIZE(alc888_2_capture_sources),
+               .input_mux = alc888_2_capture_sources,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc888_acer_aspire_4930g_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC888_ACER_ASPIRE_6530G] = {
+               .mixers = { alc888_acer_aspire_6530_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+                               alc888_acer_aspire_6530g_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+               .adc_nids = alc883_adc_nids_rev,
+               .capsrc_nids = alc883_capsrc_nids_rev,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .num_mux_defs =
+                       ARRAY_SIZE(alc888_2_capture_sources),
+               .input_mux = alc888_acer_aspire_6530_sources,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc888_acer_aspire_6530g_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC888_ACER_ASPIRE_8930G] = {
+               .mixers = { alc889_acer_aspire_8930g_mixer,
+                               alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+                               alc889_acer_aspire_8930g_verbs,
+                               alc889_eapd_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
+               .adc_nids = alc889_adc_nids,
+               .capsrc_nids = alc889_capsrc_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .const_channel_count = 6,
+               .num_mux_defs =
+                       ARRAY_SIZE(alc889_capture_sources),
+               .input_mux = alc889_capture_sources,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc889_acer_aspire_8930g_setup,
+               .init_hook = alc_hp_automute,
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+               .power_hook = alc_power_eapd,
+#endif
+       },
+       [ALC888_ACER_ASPIRE_7730G] = {
+               .mixers = { alc883_3ST_6ch_mixer,
+                               alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+                               alc888_acer_aspire_7730G_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+               .adc_nids = alc883_adc_nids_rev,
+               .capsrc_nids = alc883_capsrc_nids_rev,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .const_channel_count = 6,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc888_acer_aspire_7730g_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC883_MEDION] = {
+               .mixers = { alc883_fivestack_mixer,
+                           alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs,
+                               alc883_medion_eapd_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .adc_nids = alc883_adc_nids_alt,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
+               .capsrc_nids = alc883_capsrc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC883_MEDION_WIM2160] = {
+               .mixers = { alc883_medion_wim2160_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc883_medion_wim2160_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC883_LAPTOP_EAPD] = {
+               .mixers = { alc883_base_mixer },
+               .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC883_CLEVO_M540R] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
+               .channel_mode = alc883_3ST_6ch_clevo_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+               /* This machine has the hardware HP auto-muting, thus
+                * we need no software mute via unsol event
+                */
+       },
+       [ALC883_CLEVO_M720] = {
+               .mixers = { alc883_clevo_m720_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc883_clevo_m720_unsol_event,
+               .setup = alc883_clevo_m720_setup,
+               .init_hook = alc883_clevo_m720_init_hook,
+       },
+       [ALC883_LENOVO_101E_2ch] = {
+               .mixers = { alc883_lenovo_101e_2ch_mixer},
+               .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .adc_nids = alc883_adc_nids_alt,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
+               .capsrc_nids = alc883_capsrc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_lenovo_101e_capture_source,
+               .setup = alc883_lenovo_101e_setup,
+               .unsol_event = alc_sku_unsol_event,
+               .init_hook = alc_inithook,
+       },
+       [ALC883_LENOVO_NB0763] = {
+               .mixers = { alc883_lenovo_nb0763_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_lenovo_nb0763_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc883_lenovo_nb0763_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC888_LENOVO_MS7195_DIG] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc888_lenovo_ms7195_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC883_HAIER_W66] = {
+               .mixers = { alc883_targa_2ch_mixer},
+               .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc883_haier_w66_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC888_3ST_HP] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
+               .channel_mode = alc888_3st_hp_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc888_3st_hp_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC888_6ST_DELL] = {
+               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc888_6st_dell_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC883_MITAC] = {
+               .mixers = { alc883_mitac_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc883_mitac_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC883_FUJITSU_PI2515] = {
+               .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
+               .init_verbs = { alc883_init_verbs,
+                               alc883_2ch_fujitsu_pi2515_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_fujitsu_pi2515_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc883_2ch_fujitsu_pi2515_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC888_FUJITSU_XA3530] = {
+               .mixers = { alc888_base_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs,
+                       alc888_fujitsu_xa3530_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+               .adc_nids = alc883_adc_nids_rev,
+               .capsrc_nids = alc883_capsrc_nids_rev,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
+               .channel_mode = alc888_4ST_8ch_intel_modes,
+               .num_mux_defs =
+                       ARRAY_SIZE(alc888_2_capture_sources),
+               .input_mux = alc888_2_capture_sources,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc888_fujitsu_xa3530_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC888_LENOVO_SKY] = {
+               .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_lenovo_sky_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc888_lenovo_sky_setup,
+               .init_hook = alc_hp_automute,
+       },
+       [ALC888_ASUS_M90V] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_fujitsu_pi2515_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc883_mode2_setup,
+               .init_hook = alc_inithook,
+       },
+       [ALC888_ASUS_EEE1601] = {
+               .mixers = { alc883_asus_eee1601_mixer },
+               .cap_mixer = alc883_asus_eee1601_cap_mixer,
+               .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_asus_eee1601_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .init_hook = alc883_eee1601_inithook,
+       },
+       [ALC1200_ASUS_P5Q] = {
+               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC1200_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .slave_dig_outs = alc1200_slave_dig_outs,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC889A_MB31] = {
+               .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
+               .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
+                       alc880_gpio1_init_verbs },
+               .adc_nids = alc883_adc_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .capsrc_nids = alc883_capsrc_nids,
+               .dac_nids = alc883_dac_nids,
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .channel_mode = alc889A_mb31_6ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
+               .input_mux = &alc889A_mb31_capture_source,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .unsol_event = alc889A_mb31_unsol_event,
+               .init_hook = alc889A_mb31_automute,
+       },
+       [ALC883_SONY_VAIO_TT] = {
+               .mixers = { alc883_vaiott_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_sku_unsol_event,
+               .setup = alc883_vaiott_setup,
+               .init_hook = alc_hp_automute,
+       },
+};
+
+
diff --git a/sound/pci/hda/alc_quirks.c b/sound/pci/hda/alc_quirks.c
new file mode 100644 (file)
index 0000000..2be1129
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Common codes for Realtek codec quirks
+ * included by patch_realtek.c
+ */
+
+/*
+ * configuration template - to be copied to the spec instance
+ */
+struct alc_config_preset {
+       const struct snd_kcontrol_new *mixers[5]; /* should be identical size
+                                            * with spec
+                                            */
+       const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
+       const struct hda_verb *init_verbs[5];
+       unsigned int num_dacs;
+       const hda_nid_t *dac_nids;
+       hda_nid_t dig_out_nid;          /* optional */
+       hda_nid_t hp_nid;               /* optional */
+       const hda_nid_t *slave_dig_outs;
+       unsigned int num_adc_nids;
+       const hda_nid_t *adc_nids;
+       const hda_nid_t *capsrc_nids;
+       hda_nid_t dig_in_nid;
+       unsigned int num_channel_mode;
+       const struct hda_channel_mode *channel_mode;
+       int need_dac_fix;
+       int const_channel_count;
+       unsigned int num_mux_defs;
+       const struct hda_input_mux *input_mux;
+       void (*unsol_event)(struct hda_codec *, unsigned int);
+       void (*setup)(struct hda_codec *);
+       void (*init_hook)(struct hda_codec *);
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       const struct hda_amp_list *loopbacks;
+       void (*power_hook)(struct hda_codec *codec);
+#endif
+};
+
+/*
+ * channel mode setting
+ */
+static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
+                                   spec->num_channel_mode);
+}
+
+static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
+                                  spec->num_channel_mode,
+                                  spec->ext_channel_count);
+}
+
+static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
+                                     spec->num_channel_mode,
+                                     &spec->ext_channel_count);
+       if (err >= 0 && !spec->const_channel_count) {
+               spec->multiout.max_channels = spec->ext_channel_count;
+               if (spec->need_dac_fix)
+                       spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+       }
+       return err;
+}
+
+/*
+ * Control the mode of pin widget settings via the mixer.  "pc" is used
+ * instead of "%" to avoid consequences of accidentally treating the % as
+ * being part of a format specifier.  Maximum allowed length of a value is
+ * 63 characters plus NULL terminator.
+ *
+ * Note: some retasking pin complexes seem to ignore requests for input
+ * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
+ * are requested.  Therefore order this list so that this behaviour will not
+ * cause problems when mixer clients move through the enum sequentially.
+ * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
+ * March 2006.
+ */
+static const char * const alc_pin_mode_names[] = {
+       "Mic 50pc bias", "Mic 80pc bias",
+       "Line in", "Line out", "Headphone out",
+};
+static const unsigned char alc_pin_mode_values[] = {
+       PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
+};
+/* The control can present all 5 options, or it can limit the options based
+ * in the pin being assumed to be exclusively an input or an output pin.  In
+ * addition, "input" pins may or may not process the mic bias option
+ * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
+ * accept requests for bias as of chip versions up to March 2006) and/or
+ * wiring in the computer.
+ */
+#define ALC_PIN_DIR_IN              0x00
+#define ALC_PIN_DIR_OUT             0x01
+#define ALC_PIN_DIR_INOUT           0x02
+#define ALC_PIN_DIR_IN_NOMICBIAS    0x03
+#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
+
+/* Info about the pin modes supported by the different pin direction modes.
+ * For each direction the minimum and maximum values are given.
+ */
+static const signed char alc_pin_mode_dir_info[5][2] = {
+       { 0, 2 },    /* ALC_PIN_DIR_IN */
+       { 3, 4 },    /* ALC_PIN_DIR_OUT */
+       { 0, 4 },    /* ALC_PIN_DIR_INOUT */
+       { 2, 2 },    /* ALC_PIN_DIR_IN_NOMICBIAS */
+       { 2, 4 },    /* ALC_PIN_DIR_INOUT_NOMICBIAS */
+};
+#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
+#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
+#define alc_pin_mode_n_items(_dir) \
+       (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
+
+static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int item_num = uinfo->value.enumerated.item;
+       unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
+
+       if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
+               item_num = alc_pin_mode_min(dir);
+       strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
+       return 0;
+}
+
+static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       unsigned int i;
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
+       long *valp = ucontrol->value.integer.value;
+       unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
+                                                AC_VERB_GET_PIN_WIDGET_CONTROL,
+                                                0x00);
+
+       /* Find enumerated value for current pinctl setting */
+       i = alc_pin_mode_min(dir);
+       while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
+               i++;
+       *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
+       return 0;
+}
+
+static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       signed int change;
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
+       long val = *ucontrol->value.integer.value;
+       unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
+                                                AC_VERB_GET_PIN_WIDGET_CONTROL,
+                                                0x00);
+
+       if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
+               val = alc_pin_mode_min(dir);
+
+       change = pinctl != alc_pin_mode_values[val];
+       if (change) {
+               /* Set pin mode to that requested */
+               snd_hda_codec_write_cache(codec, nid, 0,
+                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                         alc_pin_mode_values[val]);
+
+               /* Also enable the retasking pin's input/output as required
+                * for the requested pin mode.  Enum values of 2 or less are
+                * input modes.
+                *
+                * Dynamically switching the input/output buffers probably
+                * reduces noise slightly (particularly on input) so we'll
+                * do it.  However, having both input and output buffers
+                * enabled simultaneously doesn't seem to be problematic if
+                * this turns out to be necessary in the future.
+                */
+               if (val <= 2) {
+                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+                                                HDA_AMP_MUTE, HDA_AMP_MUTE);
+                       snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
+                                                HDA_AMP_MUTE, 0);
+               } else {
+                       snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
+                                                HDA_AMP_MUTE, HDA_AMP_MUTE);
+                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+                                                HDA_AMP_MUTE, 0);
+               }
+       }
+       return change;
+}
+
+#define ALC_PIN_MODE(xname, nid, dir) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
+         .info = alc_pin_mode_info, \
+         .get = alc_pin_mode_get, \
+         .put = alc_pin_mode_put, \
+         .private_value = nid | (dir<<16) }
+
+/* A switch control for ALC260 GPIO pins.  Multiple GPIOs can be ganged
+ * together using a mask with more than one bit set.  This control is
+ * currently used only by the ALC260 test model.  At this stage they are not
+ * needed for any "production" models.
+ */
+#ifdef CONFIG_SND_DEBUG
+#define alc_gpio_data_info     snd_ctl_boolean_mono_info
+
+static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long *valp = ucontrol->value.integer.value;
+       unsigned int val = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_GPIO_DATA, 0x00);
+
+       *valp = (val & mask) != 0;
+       return 0;
+}
+static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       signed int change;
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long val = *ucontrol->value.integer.value;
+       unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
+                                                   AC_VERB_GET_GPIO_DATA,
+                                                   0x00);
+
+       /* Set/unset the masked GPIO bit(s) as needed */
+       change = (val == 0 ? 0 : mask) != (gpio_data & mask);
+       if (val == 0)
+               gpio_data &= ~mask;
+       else
+               gpio_data |= mask;
+       snd_hda_codec_write_cache(codec, nid, 0,
+                                 AC_VERB_SET_GPIO_DATA, gpio_data);
+
+       return change;
+}
+#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
+         .info = alc_gpio_data_info, \
+         .get = alc_gpio_data_get, \
+         .put = alc_gpio_data_put, \
+         .private_value = nid | (mask<<16) }
+#endif   /* CONFIG_SND_DEBUG */
+
+/* A switch control to allow the enabling of the digital IO pins on the
+ * ALC260.  This is incredibly simplistic; the intention of this control is
+ * to provide something in the test model allowing digital outputs to be
+ * identified if present.  If models are found which can utilise these
+ * outputs a more complete mixer control can be devised for those models if
+ * necessary.
+ */
+#ifdef CONFIG_SND_DEBUG
+#define alc_spdif_ctrl_info    snd_ctl_boolean_mono_info
+
+static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long *valp = ucontrol->value.integer.value;
+       unsigned int val = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_DIGI_CONVERT_1, 0x00);
+
+       *valp = (val & mask) != 0;
+       return 0;
+}
+static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       signed int change;
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long val = *ucontrol->value.integer.value;
+       unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
+                                                   AC_VERB_GET_DIGI_CONVERT_1,
+                                                   0x00);
+
+       /* Set/unset the masked control bit(s) as needed */
+       change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
+       if (val==0)
+               ctrl_data &= ~mask;
+       else
+               ctrl_data |= mask;
+       snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+                                 ctrl_data);
+
+       return change;
+}
+#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
+         .info = alc_spdif_ctrl_info, \
+         .get = alc_spdif_ctrl_get, \
+         .put = alc_spdif_ctrl_put, \
+         .private_value = nid | (mask<<16) }
+#endif   /* CONFIG_SND_DEBUG */
+
+/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
+ * Again, this is only used in the ALC26x test models to help identify when
+ * the EAPD line must be asserted for features to work.
+ */
+#ifdef CONFIG_SND_DEBUG
+#define alc_eapd_ctrl_info     snd_ctl_boolean_mono_info
+
+static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long *valp = ucontrol->value.integer.value;
+       unsigned int val = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_EAPD_BTLENABLE, 0x00);
+
+       *valp = (val & mask) != 0;
+       return 0;
+}
+
+static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       int change;
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long val = *ucontrol->value.integer.value;
+       unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
+                                                   AC_VERB_GET_EAPD_BTLENABLE,
+                                                   0x00);
+
+       /* Set/unset the masked control bit(s) as needed */
+       change = (!val ? 0 : mask) != (ctrl_data & mask);
+       if (!val)
+               ctrl_data &= ~mask;
+       else
+               ctrl_data |= mask;
+       snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                                 ctrl_data);
+
+       return change;
+}
+
+#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
+         .info = alc_eapd_ctrl_info, \
+         .get = alc_eapd_ctrl_get, \
+         .put = alc_eapd_ctrl_put, \
+         .private_value = nid | (mask<<16) }
+#endif   /* CONFIG_SND_DEBUG */
+
+static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       if (!cfg->line_outs) {
+               while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
+                      cfg->line_out_pins[cfg->line_outs])
+                       cfg->line_outs++;
+       }
+       if (!cfg->speaker_outs) {
+               while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
+                      cfg->speaker_pins[cfg->speaker_outs])
+                       cfg->speaker_outs++;
+       }
+       if (!cfg->hp_outs) {
+               while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
+                      cfg->hp_pins[cfg->hp_outs])
+                       cfg->hp_outs++;
+       }
+}
+
+/*
+ * set up from the preset table
+ */
+static void setup_preset(struct hda_codec *codec,
+                        const struct alc_config_preset *preset)
+{
+       struct alc_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
+               add_mixer(spec, preset->mixers[i]);
+       spec->cap_mixer = preset->cap_mixer;
+       for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
+            i++)
+               add_verb(spec, preset->init_verbs[i]);
+
+       spec->channel_mode = preset->channel_mode;
+       spec->num_channel_mode = preset->num_channel_mode;
+       spec->need_dac_fix = preset->need_dac_fix;
+       spec->const_channel_count = preset->const_channel_count;
+
+       if (preset->const_channel_count)
+               spec->multiout.max_channels = preset->const_channel_count;
+       else
+               spec->multiout.max_channels = spec->channel_mode[0].channels;
+       spec->ext_channel_count = spec->channel_mode[0].channels;
+
+       spec->multiout.num_dacs = preset->num_dacs;
+       spec->multiout.dac_nids = preset->dac_nids;
+       spec->multiout.dig_out_nid = preset->dig_out_nid;
+       spec->multiout.slave_dig_outs = preset->slave_dig_outs;
+       spec->multiout.hp_nid = preset->hp_nid;
+
+       spec->num_mux_defs = preset->num_mux_defs;
+       if (!spec->num_mux_defs)
+               spec->num_mux_defs = 1;
+       spec->input_mux = preset->input_mux;
+
+       spec->num_adc_nids = preset->num_adc_nids;
+       spec->adc_nids = preset->adc_nids;
+       spec->capsrc_nids = preset->capsrc_nids;
+       spec->dig_in_nid = preset->dig_in_nid;
+
+       spec->unsol_event = preset->unsol_event;
+       spec->init_hook = preset->init_hook;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       spec->power_hook = preset->power_hook;
+       spec->loopback.amplist = preset->loopbacks;
+#endif
+
+       if (preset->setup)
+               preset->setup(codec);
+
+       alc_fixup_autocfg_pin_nums(codec);
+}
+
+
+/* auto-toggle front mic */
+static void alc88x_simple_mic_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_jack_detect(codec, 0x18);
+       bits = present ? HDA_AMP_MUTE : 0;
+       snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
+}
+
index 45b4a8d..9c27a3a 100644 (file)
@@ -243,7 +243,8 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
 {
        unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
        unsigned int res;
-       codec_exec_verb(codec, cmd, &res);
+       if (codec_exec_verb(codec, cmd, &res))
+               return -1;
        return res;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_read);
@@ -307,63 +308,107 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
 
-static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
-                               hda_nid_t *conn_list, int max_conns);
-static bool add_conn_list(struct snd_array *array, hda_nid_t nid);
-static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
-                         hda_nid_t *src, int len);
+/* look up the cached results */
+static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid)
+{
+       int i, len;
+       for (i = 0; i < array->used; ) {
+               hda_nid_t *p = snd_array_elem(array, i);
+               if (nid == *p)
+                       return p;
+               len = p[1];
+               i += len + 2;
+       }
+       return NULL;
+}
 
 /**
- * snd_hda_get_connections - get connection list
+ * snd_hda_get_conn_list - get connection list
  * @codec: the HDA codec
  * @nid: NID to parse
- * @conn_list: connection list array
- * @max_conns: max. number of connections to store
+ * @listp: the pointer to store NID list
  *
  * Parses the connection list of the given widget and stores the list
  * of NIDs.
  *
  * Returns the number of connections, or a negative error code.
  */
-int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
-                            hda_nid_t *conn_list, int max_conns)
+int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
+                         const hda_nid_t **listp)
 {
        struct snd_array *array = &codec->conn_lists;
-       int i, len, old_used;
+       int len, err;
        hda_nid_t list[HDA_MAX_CONNECTIONS];
+       hda_nid_t *p;
+       bool added = false;
 
-       /* look up the cached results */
-       for (i = 0; i < array->used; ) {
-               hda_nid_t *p = snd_array_elem(array, i);
-               len = p[1];
-               if (nid == *p)
-                       return copy_conn_list(nid, conn_list, max_conns,
-                                             p + 2, len);
-               i += len + 2;
+ again:
+       /* if the connection-list is already cached, read it */
+       p = lookup_conn_list(array, nid);
+       if (p) {
+               if (listp)
+                       *listp = p + 2;
+               return p[1];
        }
+       if (snd_BUG_ON(added))
+               return -EINVAL;
 
-       len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
+       /* read the connection and add to the cache */
+       len = snd_hda_get_raw_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
        if (len < 0)
                return len;
+       err = snd_hda_override_conn_list(codec, nid, len, list);
+       if (err < 0)
+               return err;
+       added = true;
+       goto again;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_conn_list);
 
-       /* add to the cache */
-       old_used = array->used;
-       if (!add_conn_list(array, nid) || !add_conn_list(array, len))
-               goto error_add;
-       for (i = 0; i < len; i++)
-               if (!add_conn_list(array, list[i]))
-                       goto error_add;
+/**
+ * snd_hda_get_connections - copy connection list
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @conn_list: connection list array
+ * @max_conns: max. number of connections to store
+ *
+ * Parses the connection list of the given widget and stores the list
+ * of NIDs.
+ *
+ * Returns the number of connections, or a negative error code.
+ */
+int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+                            hda_nid_t *conn_list, int max_conns)
+{
+       const hda_nid_t *list;
+       int len = snd_hda_get_conn_list(codec, nid, &list);
 
-       return copy_conn_list(nid, conn_list, max_conns, list, len);
-               
- error_add:
-       array->used = old_used;
-       return -ENOMEM;
+       if (len <= 0)
+               return len;
+       if (len > max_conns) {
+               snd_printk(KERN_ERR "hda_codec: "
+                          "Too many connections %d for NID 0x%x\n",
+                          len, nid);
+               return -EINVAL;
+       }
+       memcpy(conn_list, list, len * sizeof(hda_nid_t));
+       return len;
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_connections);
 
-static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
-                            hda_nid_t *conn_list, int max_conns)
+/**
+ * snd_hda_get_raw_connections - copy connection list without cache
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @conn_list: connection list array
+ * @max_conns: max. number of connections to store
+ *
+ * Like snd_hda_get_connections(), copy the connection list but without
+ * checking through the connection-list cache.
+ * Currently called only from hda_proc.c, so not exported.
+ */
+int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
+                               hda_nid_t *conn_list, int max_conns)
 {
        unsigned int parm;
        int i, conn_len, conns;
@@ -376,11 +421,8 @@ static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 
        wcaps = get_wcaps(codec, nid);
        if (!(wcaps & AC_WCAP_CONN_LIST) &&
-           get_wcaps_type(wcaps) != AC_WID_VOL_KNB) {
-               snd_printk(KERN_WARNING "hda_codec: "
-                          "connection list not available for 0x%x\n", nid);
-               return -EINVAL;
-       }
+           get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+               return 0;
 
        parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
        if (parm & AC_CLIST_LONG) {
@@ -470,18 +512,77 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
        return true;
 }
 
-static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
-                         hda_nid_t *src, int len)
+/**
+ * snd_hda_override_conn_list - add/modify the connection-list to cache
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @len: number of connection list entries
+ * @list: the list of connection entries
+ *
+ * Add or modify the given connection-list to the cache.  If the corresponding
+ * cache already exists, invalidate it and append a new one.
+ *
+ * Returns zero or a negative error code.
+ */
+int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
+                              const hda_nid_t *list)
 {
-       if (len > max_dst) {
-               snd_printk(KERN_ERR "hda_codec: "
-                          "Too many connections %d for NID 0x%x\n",
-                          len, nid);
-               return -EINVAL;
+       struct snd_array *array = &codec->conn_lists;
+       hda_nid_t *p;
+       int i, old_used;
+
+       p = lookup_conn_list(array, nid);
+       if (p)
+               *p = -1; /* invalidate the old entry */
+
+       old_used = array->used;
+       if (!add_conn_list(array, nid) || !add_conn_list(array, len))
+               goto error_add;
+       for (i = 0; i < len; i++)
+               if (!add_conn_list(array, list[i]))
+                       goto error_add;
+       return 0;
+
+ error_add:
+       array->used = old_used;
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
+
+/**
+ * snd_hda_get_conn_index - get the connection index of the given NID
+ * @codec: the HDA codec
+ * @mux: NID containing the list
+ * @nid: NID to select
+ * @recursive: 1 when searching NID recursively, otherwise 0
+ *
+ * Parses the connection list of the widget @mux and checks whether the
+ * widget @nid is present.  If it is, return the connection index.
+ * Otherwise it returns -1.
+ */
+int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
+                          hda_nid_t nid, int recursive)
+{
+       hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+       int i, nums;
+
+       nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+       for (i = 0; i < nums; i++)
+               if (conn[i] == nid)
+                       return i;
+       if (!recursive)
+               return -1;
+       if (recursive > 5) {
+               snd_printd("hda_codec: too deep connection for 0x%x\n", nid);
+               return -1;
        }
-       memcpy(dst, src, len * sizeof(hda_nid_t));
-       return len;
+       recursive++;
+       for (i = 0; i < nums; i++)
+               if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0)
+                       return i;
+       return -1;
 }
+EXPORT_SYMBOL_HDA(snd_hda_get_conn_index);
 
 /**
  * snd_hda_queue_unsol_event - add an unsolicited event to queue
@@ -1083,6 +1184,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
        snd_array_free(&codec->mixers);
        snd_array_free(&codec->nids);
        snd_array_free(&codec->conn_lists);
+       snd_array_free(&codec->spdif_out);
        codec->bus->caddr_tbl[codec->addr] = NULL;
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
@@ -1144,6 +1246,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
        snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
        snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
        snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
+       snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
        if (codec->bus->modelname) {
                codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
                if (!codec->modelname) {
@@ -2555,11 +2658,13 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       int idx = kcontrol->private_value;
+       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
 
-       ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff;
-       ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff;
-       ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff;
-       ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff;
+       ucontrol->value.iec958.status[0] = spdif->status & 0xff;
+       ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff;
+       ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff;
+       ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff;
 
        return 0;
 }
@@ -2644,23 +2749,23 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
+       int idx = kcontrol->private_value;
+       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+       hda_nid_t nid = spdif->nid;
        unsigned short val;
        int change;
 
        mutex_lock(&codec->spdif_mutex);
-       codec->spdif_status = ucontrol->value.iec958.status[0] |
+       spdif->status = ucontrol->value.iec958.status[0] |
                ((unsigned int)ucontrol->value.iec958.status[1] << 8) |
                ((unsigned int)ucontrol->value.iec958.status[2] << 16) |
                ((unsigned int)ucontrol->value.iec958.status[3] << 24);
-       val = convert_from_spdif_status(codec->spdif_status);
-       val |= codec->spdif_ctls & 1;
-       change = codec->spdif_ctls != val;
-       codec->spdif_ctls = val;
-
-       if (change)
+       val = convert_from_spdif_status(spdif->status);
+       val |= spdif->ctls & 1;
+       change = spdif->ctls != val;
+       spdif->ctls = val;
+       if (change && nid != (u16)-1)
                set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
-
        mutex_unlock(&codec->spdif_mutex);
        return change;
 }
@@ -2671,33 +2776,42 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       int idx = kcontrol->private_value;
+       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
 
-       ucontrol->value.integer.value[0] = codec->spdif_ctls & AC_DIG1_ENABLE;
+       ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE;
        return 0;
 }
 
+static inline void set_spdif_ctls(struct hda_codec *codec, hda_nid_t nid,
+                                 int dig1, int dig2)
+{
+       set_dig_out_convert(codec, nid, dig1, dig2);
+       /* unmute amp switch (if any) */
+       if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
+           (dig1 & AC_DIG1_ENABLE))
+               snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+                                           HDA_AMP_MUTE, 0);
+}
+
 static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
+       int idx = kcontrol->private_value;
+       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+       hda_nid_t nid = spdif->nid;
        unsigned short val;
        int change;
 
        mutex_lock(&codec->spdif_mutex);
-       val = codec->spdif_ctls & ~AC_DIG1_ENABLE;
+       val = spdif->ctls & ~AC_DIG1_ENABLE;
        if (ucontrol->value.integer.value[0])
                val |= AC_DIG1_ENABLE;
-       change = codec->spdif_ctls != val;
-       if (change) {
-               codec->spdif_ctls = val;
-               set_dig_out_convert(codec, nid, val & 0xff, -1);
-               /* unmute amp switch (if any) */
-               if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
-                   (val & AC_DIG1_ENABLE))
-                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE, 0);
-       }
+       change = spdif->ctls != val;
+       spdif->ctls = val;
+       if (change && nid != (u16)-1)
+               set_spdif_ctls(codec, nid, val & 0xff, -1);
        mutex_unlock(&codec->spdif_mutex);
        return change;
 }
@@ -2744,36 +2858,79 @@ static struct snd_kcontrol_new dig_mixes[] = {
  *
  * Returns 0 if successful, or a negative error code.
  */
-int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
+int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
+                                 hda_nid_t associated_nid,
+                                 hda_nid_t cvt_nid)
 {
        int err;
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_new *dig_mix;
        int idx;
+       struct hda_spdif_out *spdif;
 
        idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch");
        if (idx < 0) {
                printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
                return -EBUSY;
        }
+       spdif = snd_array_new(&codec->spdif_out);
        for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
                kctl = snd_ctl_new1(dig_mix, codec);
                if (!kctl)
                        return -ENOMEM;
                kctl->id.index = idx;
-               kctl->private_value = nid;
-               err = snd_hda_ctl_add(codec, nid, kctl);
+               kctl->private_value = codec->spdif_out.used - 1;
+               err = snd_hda_ctl_add(codec, associated_nid, kctl);
                if (err < 0)
                        return err;
        }
-       codec->spdif_ctls =
-               snd_hda_codec_read(codec, nid, 0,
-                                  AC_VERB_GET_DIGI_CONVERT_1, 0);
-       codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls);
+       spdif->nid = cvt_nid;
+       spdif->ctls = snd_hda_codec_read(codec, cvt_nid, 0,
+                                        AC_VERB_GET_DIGI_CONVERT_1, 0);
+       spdif->status = convert_to_spdif_status(spdif->ctls);
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls);
 
+struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
+                                              hda_nid_t nid)
+{
+       int i;
+       for (i = 0; i < codec->spdif_out.used; i++) {
+               struct hda_spdif_out *spdif =
+                               snd_array_elem(&codec->spdif_out, i);
+               if (spdif->nid == nid)
+                       return spdif;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid);
+
+void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
+{
+       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+
+       mutex_lock(&codec->spdif_mutex);
+       spdif->nid = (u16)-1;
+       mutex_unlock(&codec->spdif_mutex);
+}
+EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign);
+
+void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
+{
+       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+       unsigned short val;
+
+       mutex_lock(&codec->spdif_mutex);
+       if (spdif->nid != nid) {
+               spdif->nid = nid;
+               val = spdif->ctls;
+               set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff);
+       }
+       mutex_unlock(&codec->spdif_mutex);
+}
+EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign);
+
 /*
  * SPDIF sharing with analog output
  */
@@ -3356,7 +3513,7 @@ static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
  *
  * Returns 0 if successful, otherwise a negative error code.
  */
-static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
                                u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
 {
        unsigned int i, val, wcaps;
@@ -3448,6 +3605,7 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 
        return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_query_supported_pcm);
 
 /**
  * snd_hda_is_supported_format - Check the validity of the format
@@ -4177,10 +4335,12 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put);
 static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
                                 unsigned int stream_tag, unsigned int format)
 {
+       struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(codec, nid);
+
        /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
                set_dig_out_convert(codec, nid,
-                                   codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
+                                   spdif->ctls & ~AC_DIG1_ENABLE & 0xff,
                                    -1);
        snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
        if (codec->slave_dig_outs) {
@@ -4190,9 +4350,9 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
                                                   format);
        }
        /* turn on again (if needed) */
-       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
                set_dig_out_convert(codec, nid,
-                                   codec->spdif_ctls & 0xff, -1);
+                                   spdif->ctls & 0xff, -1);
 }
 
 static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
@@ -4348,6 +4508,8 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
 {
        const hda_nid_t *nids = mout->dac_nids;
        int chs = substream->runtime->channels;
+       struct hda_spdif_out *spdif =
+                       snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
        int i;
 
        mutex_lock(&codec->spdif_mutex);
@@ -4356,7 +4518,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
                if (chs == 2 &&
                    snd_hda_is_supported_format(codec, mout->dig_out_nid,
                                                format) &&
-                   !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
+                   !(spdif->status & IEC958_AES0_NONAUDIO)) {
                        mout->dig_out_used = HDA_DIG_ANALOG_DUP;
                        setup_dig_out_stream(codec, mout->dig_out_nid,
                                             stream_tag, format);
@@ -4528,7 +4690,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                unsigned int wid_caps = get_wcaps(codec, nid);
                unsigned int wid_type = get_wcaps_type(wid_caps);
                unsigned int def_conf;
-               short assoc, loc;
+               short assoc, loc, conn, dev;
 
                /* read all default configuration for pin complex */
                if (wid_type != AC_WID_PIN)
@@ -4538,10 +4700,19 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                        continue;
 
                def_conf = snd_hda_codec_get_pincfg(codec, nid);
-               if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+               conn = get_defcfg_connect(def_conf);
+               if (conn == AC_JACK_PORT_NONE)
                        continue;
                loc = get_defcfg_location(def_conf);
-               switch (get_defcfg_device(def_conf)) {
+               dev = get_defcfg_device(def_conf);
+
+               /* workaround for buggy BIOS setups */
+               if (dev == AC_JACK_LINE_OUT) {
+                       if (conn == AC_JACK_PORT_FIXED)
+                               dev = AC_JACK_SPEAKER;
+               }
+
+               switch (dev) {
                case AC_JACK_LINE_OUT:
                        seq = get_defcfg_sequence(def_conf);
                        assoc = get_defcfg_association(def_conf);
@@ -4957,17 +5128,15 @@ void *snd_array_new(struct snd_array *array)
 {
        if (array->used >= array->alloced) {
                int num = array->alloced + array->alloc_align;
+               int size = (num + 1) * array->elem_size;
+               int oldsize = array->alloced * array->elem_size;
                void *nlist;
                if (snd_BUG_ON(num >= 4096))
                        return NULL;
-               nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL);
+               nlist = krealloc(array->list, size, GFP_KERNEL);
                if (!nlist)
                        return NULL;
-               if (array->list) {
-                       memcpy(nlist, array->list,
-                              array->elem_size * array->alloced);
-                       kfree(array->list);
-               }
+               memset(nlist + oldsize, 0, size - oldsize);
                array->list = nlist;
                array->alloced = num;
        }
index 59c9730..f465e07 100644 (file)
@@ -829,8 +829,7 @@ struct hda_codec {
 
        struct mutex spdif_mutex;
        struct mutex control_mutex;
-       unsigned int spdif_status;      /* IEC958 status bits */
-       unsigned short spdif_ctls;      /* SPDIF control bits */
+       struct snd_array spdif_out;
        unsigned int spdif_in_enable;   /* SPDIF input enable? */
        const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
        struct snd_array init_pins;     /* initial (BIOS) pin configurations */
@@ -904,6 +903,16 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
                          hda_nid_t *start_id);
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
                            hda_nid_t *conn_list, int max_conns);
+int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
+                           hda_nid_t *conn_list, int max_conns);
+int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
+                         const hda_nid_t **listp);
+int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
+                         const hda_nid_t *list);
+int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
+                          hda_nid_t nid, int recursive);
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+                               u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
 
 struct hda_verb {
        hda_nid_t nid;
@@ -947,6 +956,17 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
                       hda_nid_t nid, unsigned int cfg); /* for hwdep */
 void snd_hda_shutup_pins(struct hda_codec *codec);
 
+/* SPDIF controls */
+struct hda_spdif_out {
+       hda_nid_t nid;          /* Converter nid values relate to */
+       unsigned int status;    /* IEC958 status bits */
+       unsigned short ctls;    /* SPDIF control bits */
+};
+struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
+                                              hda_nid_t nid);
+void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx);
+void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid);
+
 /*
  * Mixer
  */
@@ -997,17 +1017,15 @@ int snd_hda_suspend(struct hda_bus *bus);
 int snd_hda_resume(struct hda_bus *bus);
 #endif
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
 static inline
 int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
+#ifdef CONFIG_SND_HDA_POWER_SAVE
        if (codec->patch_ops.check_power_status)
                return codec->patch_ops.check_power_status(codec, nid);
+#endif
        return 0;
 }
-#else  
-#define hda_call_check_power_status(codec, nid)                0
-#endif
 
 /*
  * get widget information
index e3e8531..28ce17d 100644 (file)
@@ -580,43 +580,45 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
 #endif /* CONFIG_PROC_FS */
 
 /* update PCM info based on ELD */
-void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
-                             struct hda_pcm_stream *codec_pars)
+void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
+                             struct hda_pcm_stream *hinfo)
 {
+       u32 rates;
+       u64 formats;
+       unsigned int maxbps;
+       unsigned int channels_max;
        int i;
 
        /* assume basic audio support (the basic audio flag is not in ELD;
         * however, all audio capable sinks are required to support basic
         * audio) */
-       pcm->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
-       pcm->formats = SNDRV_PCM_FMTBIT_S16_LE;
-       pcm->maxbps = 16;
-       pcm->channels_max = 2;
+       rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+               SNDRV_PCM_RATE_48000;
+       formats = SNDRV_PCM_FMTBIT_S16_LE;
+       maxbps = 16;
+       channels_max = 2;
        for (i = 0; i < eld->sad_count; i++) {
                struct cea_sad *a = &eld->sad[i];
-               pcm->rates |= a->rates;
-               if (a->channels > pcm->channels_max)
-                       pcm->channels_max = a->channels;
+               rates |= a->rates;
+               if (a->channels > channels_max)
+                       channels_max = a->channels;
                if (a->format == AUDIO_CODING_TYPE_LPCM) {
                        if (a->sample_bits & AC_SUPPCM_BITS_20) {
-                               pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE;
-                               if (pcm->maxbps < 20)
-                                       pcm->maxbps = 20;
+                               formats |= SNDRV_PCM_FMTBIT_S32_LE;
+                               if (maxbps < 20)
+                                       maxbps = 20;
                        }
                        if (a->sample_bits & AC_SUPPCM_BITS_24) {
-                               pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE;
-                               if (pcm->maxbps < 24)
-                                       pcm->maxbps = 24;
+                               formats |= SNDRV_PCM_FMTBIT_S32_LE;
+                               if (maxbps < 24)
+                                       maxbps = 24;
                        }
                }
        }
 
-       if (!codec_pars)
-               return;
-
        /* restrict the parameters by the values the codec provides */
-       pcm->rates &= codec_pars->rates;
-       pcm->formats &= codec_pars->formats;
-       pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
-       pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
+       hinfo->rates &= rates;
+       hinfo->formats &= formats;
+       hinfo->maxbps = min(hinfo->maxbps, maxbps);
+       hinfo->channels_max = min(hinfo->channels_max, channels_max);
 }
index 486f6de..be69822 100644 (file)
@@ -177,7 +177,8 @@ MODULE_DESCRIPTION("Intel HDA driver");
 #define ICH6_REG_INTCTL                        0x20
 #define ICH6_REG_INTSTS                        0x24
 #define ICH6_REG_WALLCLK               0x30    /* 24Mhz source */
-#define ICH6_REG_SYNC                  0x34    
+#define ICH6_REG_OLD_SSYNC             0x34    /* SSYNC for old ICH */
+#define ICH6_REG_SSYNC                 0x38
 #define ICH6_REG_CORBLBASE             0x40
 #define ICH6_REG_CORBUBASE             0x44
 #define ICH6_REG_CORBWP                        0x48
@@ -479,6 +480,7 @@ enum {
 #define AZX_DCAPS_POSFIX_VIA   (1 << 17)       /* Use VIACOMBO as default */
 #define AZX_DCAPS_NO_64BIT     (1 << 18)       /* No 64bit address */
 #define AZX_DCAPS_SYNC_WRITE   (1 << 19)       /* sync each cmd write */
+#define AZX_DCAPS_OLD_SSYNC    (1 << 20)       /* Old SSYNC reg for ICH */
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -1706,13 +1708,16 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        unsigned int bufsize, period_bytes, format_val, stream_tag;
        int err;
+       struct hda_spdif_out *spdif =
+               snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
+       unsigned short ctls = spdif ? spdif->ctls : 0;
 
        azx_stream_reset(chip, azx_dev);
        format_val = snd_hda_calc_stream_format(runtime->rate,
                                                runtime->channels,
                                                runtime->format,
                                                hinfo->maxbps,
-                                               apcm->codec->spdif_ctls);
+                                               ctls);
        if (!format_val) {
                snd_printk(KERN_ERR SFX
                           "invalid format_val, rate=%d, ch=%d, format=%d\n",
@@ -1792,7 +1797,11 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        spin_lock(&chip->reg_lock);
        if (nsync > 1) {
                /* first, set SYNC bits of corresponding streams */
-               azx_writel(chip, SYNC, azx_readl(chip, SYNC) | sbits);
+               if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+                       azx_writel(chip, OLD_SSYNC,
+                                  azx_readl(chip, OLD_SSYNC) | sbits);
+               else
+                       azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
        }
        snd_pcm_group_for_each_entry(s, substream) {
                if (s->pcm->card != substream->pcm->card)
@@ -1848,7 +1857,11 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        if (nsync > 1) {
                spin_lock(&chip->reg_lock);
                /* reset SYNC bits */
-               azx_writel(chip, SYNC, azx_readl(chip, SYNC) & ~sbits);
+               if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+                       azx_writel(chip, OLD_SSYNC,
+                                  azx_readl(chip, OLD_SSYNC) & ~sbits);
+               else
+                       azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
                spin_unlock(&chip->reg_lock);
        }
        return 0;
@@ -1863,7 +1876,7 @@ static unsigned int azx_via_get_position(struct azx *chip,
        unsigned int fifo_size;
 
        link_pos = azx_sd_readl(azx_dev, SD_LPIB);
-       if (azx_dev->index >= 4) {
+       if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                /* Playback, no problem using link position */
                return link_pos;
        }
@@ -1927,6 +1940,17 @@ static unsigned int azx_get_position(struct azx *chip,
        default:
                /* use the position buffer */
                pos = le32_to_cpu(*azx_dev->posbuf);
+               if (chip->position_fix[stream] == POS_FIX_AUTO) {
+                       if (!pos || pos == (u32)-1) {
+                               printk(KERN_WARNING
+                                      "hda-intel: Invalid position buffer, "
+                                      "using LPIB read method instead.\n");
+                               chip->position_fix[stream] = POS_FIX_LPIB;
+                               pos = azx_sd_readl(azx_dev, SD_LPIB);
+                       } else
+                               chip->position_fix[stream] = POS_FIX_POSBUF;
+               }
+               break;
        }
 
        if (pos >= azx_dev->bufsize)
@@ -1964,16 +1988,6 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
 
        stream = azx_dev->substream->stream;
        pos = azx_get_position(chip, azx_dev);
-       if (chip->position_fix[stream] == POS_FIX_AUTO) {
-               if (!pos) {
-                       printk(KERN_WARNING
-                              "hda-intel: Invalid position buffer, "
-                              "using LPIB read method instead.\n");
-                       chip->position_fix[stream] = POS_FIX_LPIB;
-                       pos = azx_get_position(chip, azx_dev);
-               } else
-                       chip->position_fix[stream] = POS_FIX_POSBUF;
-       }
 
        if (WARN_ONCE(!azx_dev->period_bytes,
                      "hda-intel: zero azx_dev->period_bytes"))
@@ -2061,6 +2075,8 @@ static void azx_pcm_free(struct snd_pcm *pcm)
        }
 }
 
+#define MAX_PREALLOC_SIZE      (32 * 1024 * 1024)
+
 static int
 azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
                      struct hda_pcm *cpcm)
@@ -2069,6 +2085,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        struct snd_pcm *pcm;
        struct azx_pcm *apcm;
        int pcm_dev = cpcm->device;
+       unsigned int size;
        int s, err;
 
        if (pcm_dev >= HDA_MAX_PCMS) {
@@ -2104,9 +2121,12 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
                        snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
        }
        /* buffer pre-allocation */
+       size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
+       if (size > MAX_PREALLOC_SIZE)
+               size = MAX_PREALLOC_SIZE;
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                                              snd_dma_pci_data(chip->pci),
-                                             1024 * 64, 32 * 1024 * 1024);
+                                             size, MAX_PREALLOC_SIZE);
        return 0;
 }
 
@@ -2149,7 +2169,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
 {
        if (request_irq(chip->pci->irq, azx_interrupt,
                        chip->msi ? 0 : IRQF_SHARED,
-                       "hda_intel", chip)) {
+                       KBUILD_MODNAME, chip)) {
                printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
                       "disabling device\n", chip->pci->irq);
                if (do_disconnect)
@@ -2347,28 +2367,20 @@ static int azx_dev_free(struct snd_device *device)
  * white/black-listing for position_fix
  */
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
-       SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1025, 0x026f, "Acer Aspire 5538", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1043, 0x8410, "ASUS", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB),
        {}
 };
 
@@ -2815,6 +2827,22 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* SCH */
        { PCI_DEVICE(0x8086, 0x811b),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP },
+       { PCI_DEVICE(0x8086, 0x2668),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH6 */
+       { PCI_DEVICE(0x8086, 0x27d8),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH7 */
+       { PCI_DEVICE(0x8086, 0x269a),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ESB2 */
+       { PCI_DEVICE(0x8086, 0x284b),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH8 */
+       { PCI_DEVICE(0x8086, 0x293e),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH9 */
+       { PCI_DEVICE(0x8086, 0x293f),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH9 */
+       { PCI_DEVICE(0x8086, 0x3a3e),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH10 */
+       { PCI_DEVICE(0x8086, 0x3a6e),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH10 */
        /* Generic Intel */
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
@@ -2908,7 +2936,7 @@ MODULE_DEVICE_TABLE(pci, azx_ids);
 
 /* pci_driver definition */
 static struct pci_driver driver = {
-       .name = "HDA Intel",
+       .name = KBUILD_MODNAME,
        .id_table = azx_ids,
        .probe = azx_probe,
        .remove = __devexit_p(azx_remove),
index 08ec073..88b277e 100644 (file)
@@ -212,7 +212,9 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 /*
  * SPDIF I/O
  */
-int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid);
+int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
+                                 hda_nid_t associated_nid,
+                                 hda_nid_t cvt_nid);
 int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
 
 /*
@@ -563,7 +565,6 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
  * power-management
  */
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
 void snd_hda_schedule_power_save(struct hda_codec *codec);
 
 struct hda_amp_list {
@@ -580,7 +581,6 @@ struct hda_loopback_check {
 int snd_hda_check_amp_list_power(struct hda_codec *codec,
                                 struct hda_loopback_check *check,
                                 hda_nid_t nid);
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
 
 /*
  * AMP control callbacks
@@ -639,8 +639,8 @@ struct hdmi_eld {
 int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
 int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t);
 void snd_hdmi_show_eld(struct hdmi_eld *eld);
-void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
-                             struct hda_pcm_stream *codec_pars);
+void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
+                             struct hda_pcm_stream *hinfo);
 
 #ifdef CONFIG_PROC_FS
 int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
index bfe74c2..2be57b0 100644 (file)
@@ -636,7 +636,7 @@ static void print_codec_info(struct snd_info_entry *entry,
                        wid_caps |= AC_WCAP_CONN_LIST;
 
                if (wid_caps & AC_WCAP_CONN_LIST)
-                       conn_len = snd_hda_get_connections(codec, nid, conn,
+                       conn_len = snd_hda_get_raw_connections(codec, nid, conn,
                                                           HDA_MAX_CONNECTIONS);
 
                if (wid_caps & AC_WCAP_IN_AMP) {
index d694e9d..1362c8b 100644 (file)
@@ -213,7 +213,9 @@ static int ad198x_build_controls(struct hda_codec *codec)
                        return err;
        }
        if (spec->multiout.dig_out_nid) {
-               err = snd_hda_create_spdif_out_ctls(codec, 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,
@@ -1920,7 +1922,8 @@ static int patch_ad1981(struct hda_codec *codec)
                spec->mixers[0] = ad1981_hp_mixers;
                spec->num_init_verbs = 2;
                spec->init_verbs[1] = ad1981_hp_init_verbs;
-               spec->multiout.dig_out_nid = 0;
+               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;
index 61b9263..6b40684 100644 (file)
@@ -240,7 +240,8 @@ static int ca0110_build_controls(struct hda_codec *codec)
        }
 
        if (spec->dig_out) {
-               err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out);
+               err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
+                                                   spec->dig_out);
                if (err < 0)
                        return err;
                err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
new file mode 100644 (file)
index 0000000..d9a2254
--- /dev/null
@@ -0,0 +1,1097 @@
+/*
+ * HD audio interface patch for Creative CA0132 chip
+ *
+ * Copyright (c) 2011, Creative Technology Ltd.
+ *
+ * Based on patch_ca0110.c
+ * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+#define WIDGET_CHIP_CTRL      0x15
+#define WIDGET_DSP_CTRL       0x16
+
+#define WUH_MEM_CONNID        10
+#define DSP_MEM_CONNID        16
+
+enum hda_cmd_vendor_io {
+       /* for DspIO node */
+       VENDOR_DSPIO_SCP_WRITE_DATA_LOW      = 0x000,
+       VENDOR_DSPIO_SCP_WRITE_DATA_HIGH     = 0x100,
+
+       VENDOR_DSPIO_STATUS                  = 0xF01,
+       VENDOR_DSPIO_SCP_POST_READ_DATA      = 0x702,
+       VENDOR_DSPIO_SCP_READ_DATA           = 0xF02,
+       VENDOR_DSPIO_DSP_INIT                = 0x703,
+       VENDOR_DSPIO_SCP_POST_COUNT_QUERY    = 0x704,
+       VENDOR_DSPIO_SCP_READ_COUNT          = 0xF04,
+
+       /* for ChipIO node */
+       VENDOR_CHIPIO_ADDRESS_LOW            = 0x000,
+       VENDOR_CHIPIO_ADDRESS_HIGH           = 0x100,
+       VENDOR_CHIPIO_STREAM_FORMAT          = 0x200,
+       VENDOR_CHIPIO_DATA_LOW               = 0x300,
+       VENDOR_CHIPIO_DATA_HIGH              = 0x400,
+
+       VENDOR_CHIPIO_GET_PARAMETER          = 0xF00,
+       VENDOR_CHIPIO_STATUS                 = 0xF01,
+       VENDOR_CHIPIO_HIC_POST_READ          = 0x702,
+       VENDOR_CHIPIO_HIC_READ_DATA          = 0xF03,
+
+       VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE   = 0x70A,
+
+       VENDOR_CHIPIO_PLL_PMU_WRITE          = 0x70C,
+       VENDOR_CHIPIO_PLL_PMU_READ           = 0xF0C,
+       VENDOR_CHIPIO_8051_ADDRESS_LOW       = 0x70D,
+       VENDOR_CHIPIO_8051_ADDRESS_HIGH      = 0x70E,
+       VENDOR_CHIPIO_FLAG_SET               = 0x70F,
+       VENDOR_CHIPIO_FLAGS_GET              = 0xF0F,
+       VENDOR_CHIPIO_PARAMETER_SET          = 0x710,
+       VENDOR_CHIPIO_PARAMETER_GET          = 0xF10,
+
+       VENDOR_CHIPIO_PORT_ALLOC_CONFIG_SET  = 0x711,
+       VENDOR_CHIPIO_PORT_ALLOC_SET         = 0x712,
+       VENDOR_CHIPIO_PORT_ALLOC_GET         = 0xF12,
+       VENDOR_CHIPIO_PORT_FREE_SET          = 0x713,
+
+       VENDOR_CHIPIO_PARAMETER_EX_ID_GET    = 0xF17,
+       VENDOR_CHIPIO_PARAMETER_EX_ID_SET    = 0x717,
+       VENDOR_CHIPIO_PARAMETER_EX_VALUE_GET = 0xF18,
+       VENDOR_CHIPIO_PARAMETER_EX_VALUE_SET = 0x718
+};
+
+/*
+ *  Control flag IDs
+ */
+enum control_flag_id {
+       /* Connection manager stream setup is bypassed/enabled */
+       CONTROL_FLAG_C_MGR                  = 0,
+       /* DSP DMA is bypassed/enabled */
+       CONTROL_FLAG_DMA                    = 1,
+       /* 8051 'idle' mode is disabled/enabled */
+       CONTROL_FLAG_IDLE_ENABLE            = 2,
+       /* Tracker for the SPDIF-in path is bypassed/enabled */
+       CONTROL_FLAG_TRACKER                = 3,
+       /* DigitalOut to Spdif2Out connection is disabled/enabled */
+       CONTROL_FLAG_SPDIF2OUT              = 4,
+       /* Digital Microphone is disabled/enabled */
+       CONTROL_FLAG_DMIC                   = 5,
+       /* ADC_B rate is 48 kHz/96 kHz */
+       CONTROL_FLAG_ADC_B_96KHZ            = 6,
+       /* ADC_C rate is 48 kHz/96 kHz */
+       CONTROL_FLAG_ADC_C_96KHZ            = 7,
+       /* DAC rate is 48 kHz/96 kHz (affects all DACs) */
+       CONTROL_FLAG_DAC_96KHZ              = 8,
+       /* DSP rate is 48 kHz/96 kHz */
+       CONTROL_FLAG_DSP_96KHZ              = 9,
+       /* SRC clock is 98 MHz/196 MHz (196 MHz forces rate to 96 KHz) */
+       CONTROL_FLAG_SRC_CLOCK_196MHZ       = 10,
+       /* SRC rate is 48 kHz/96 kHz (48 kHz disabled when clock is 196 MHz) */
+       CONTROL_FLAG_SRC_RATE_96KHZ         = 11,
+       /* Decode Loop (DSP->SRC->DSP) is disabled/enabled */
+       CONTROL_FLAG_DECODE_LOOP            = 12,
+       /* De-emphasis filter on DAC-1 disabled/enabled */
+       CONTROL_FLAG_DAC1_DEEMPHASIS        = 13,
+       /* De-emphasis filter on DAC-2 disabled/enabled */
+       CONTROL_FLAG_DAC2_DEEMPHASIS        = 14,
+       /* De-emphasis filter on DAC-3 disabled/enabled */
+       CONTROL_FLAG_DAC3_DEEMPHASIS        = 15,
+       /* High-pass filter on ADC_B disabled/enabled */
+       CONTROL_FLAG_ADC_B_HIGH_PASS        = 16,
+       /* High-pass filter on ADC_C disabled/enabled */
+       CONTROL_FLAG_ADC_C_HIGH_PASS        = 17,
+       /* Common mode on Port_A disabled/enabled */
+       CONTROL_FLAG_PORT_A_COMMON_MODE     = 18,
+       /* Common mode on Port_D disabled/enabled */
+       CONTROL_FLAG_PORT_D_COMMON_MODE     = 19,
+       /* Impedance for ramp generator on Port_A 16 Ohm/10K Ohm */
+       CONTROL_FLAG_PORT_A_10KOHM_LOAD     = 20,
+       /* Impedance for ramp generator on Port_D, 16 Ohm/10K Ohm */
+       CONTROL_FLAG_PORT_D_10K0HM_LOAD     = 21,
+       /* ASI rate is 48kHz/96kHz */
+       CONTROL_FLAG_ASI_96KHZ              = 22,
+       /* DAC power settings able to control attached ports no/yes */
+       CONTROL_FLAG_DACS_CONTROL_PORTS     = 23,
+       /* Clock Stop OK reporting is disabled/enabled */
+       CONTROL_FLAG_CONTROL_STOP_OK_ENABLE = 24,
+       /* Number of control flags */
+       CONTROL_FLAGS_MAX = (CONTROL_FLAG_CONTROL_STOP_OK_ENABLE+1)
+};
+
+/*
+ * Control parameter IDs
+ */
+enum control_parameter_id {
+       /* 0: force HDA, 1: allow DSP if HDA Spdif1Out stream is idle */
+       CONTROL_PARAM_SPDIF1_SOURCE            = 2,
+
+       /* Stream Control */
+
+       /* Select stream with the given ID */
+       CONTROL_PARAM_STREAM_ID                = 24,
+       /* Source connection point for the selected stream */
+       CONTROL_PARAM_STREAM_SOURCE_CONN_POINT = 25,
+       /* Destination connection point for the selected stream */
+       CONTROL_PARAM_STREAM_DEST_CONN_POINT   = 26,
+       /* Number of audio channels in the selected stream */
+       CONTROL_PARAM_STREAMS_CHANNELS         = 27,
+       /*Enable control for the selected stream */
+       CONTROL_PARAM_STREAM_CONTROL           = 28,
+
+       /* Connection Point Control */
+
+       /* Select connection point with the given ID */
+       CONTROL_PARAM_CONN_POINT_ID            = 29,
+       /* Connection point sample rate */
+       CONTROL_PARAM_CONN_POINT_SAMPLE_RATE   = 30,
+
+       /* Node Control */
+
+       /* Select HDA node with the given ID */
+       CONTROL_PARAM_NODE_ID                  = 31
+};
+
+/*
+ *  Dsp Io Status codes
+ */
+enum hda_vendor_status_dspio {
+       /* Success */
+       VENDOR_STATUS_DSPIO_OK                       = 0x00,
+       /* Busy, unable to accept new command, the host must retry */
+       VENDOR_STATUS_DSPIO_BUSY                     = 0x01,
+       /* SCP command queue is full */
+       VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL   = 0x02,
+       /* SCP response queue is empty */
+       VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY = 0x03
+};
+
+/*
+ *  Chip Io Status codes
+ */
+enum hda_vendor_status_chipio {
+       /* Success */
+       VENDOR_STATUS_CHIPIO_OK   = 0x00,
+       /* Busy, unable to accept new command, the host must retry */
+       VENDOR_STATUS_CHIPIO_BUSY = 0x01
+};
+
+/*
+ *  CA0132 sample rate
+ */
+enum ca0132_sample_rate {
+       SR_6_000        = 0x00,
+       SR_8_000        = 0x01,
+       SR_9_600        = 0x02,
+       SR_11_025       = 0x03,
+       SR_16_000       = 0x04,
+       SR_22_050       = 0x05,
+       SR_24_000       = 0x06,
+       SR_32_000       = 0x07,
+       SR_44_100       = 0x08,
+       SR_48_000       = 0x09,
+       SR_88_200       = 0x0A,
+       SR_96_000       = 0x0B,
+       SR_144_000      = 0x0C,
+       SR_176_400      = 0x0D,
+       SR_192_000      = 0x0E,
+       SR_384_000      = 0x0F,
+
+       SR_COUNT        = 0x10,
+
+       SR_RATE_UNKNOWN = 0x1F
+};
+
+/*
+ *  Scp Helper function
+ */
+enum get_set {
+       IS_SET = 0,
+       IS_GET = 1,
+};
+
+/*
+ * Duplicated from ca0110 codec
+ */
+
+static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
+{
+       if (pin) {
+               snd_hda_codec_write(codec, pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+               if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
+                       snd_hda_codec_write(codec, pin, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_OUT_UNMUTE);
+       }
+       if (dac)
+               snd_hda_codec_write(codec, dac, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO);
+}
+
+static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
+{
+       if (pin) {
+               snd_hda_codec_write(codec, pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   PIN_VREF80);
+               if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
+                       snd_hda_codec_write(codec, pin, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_IN_UNMUTE(0));
+       }
+       if (adc)
+               snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_IN_UNMUTE(0));
+}
+
+static char *dirstr[2] = { "Playback", "Capture" };
+
+static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
+                      int chan, int dir)
+{
+       char namestr[44];
+       int type = dir ? HDA_INPUT : HDA_OUTPUT;
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type);
+       sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
+}
+
+static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
+                      int chan, int dir)
+{
+       char namestr[44];
+       int type = dir ? HDA_INPUT : HDA_OUTPUT;
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type);
+       sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]);
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
+}
+
+#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0)
+#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0)
+#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1)
+#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1)
+#define add_mono_switch(codec, nid, pfx, chan) \
+       _add_switch(codec, nid, pfx, chan, 0)
+#define add_mono_volume(codec, nid, pfx, chan) \
+       _add_volume(codec, nid, pfx, chan, 0)
+#define add_in_mono_switch(codec, nid, pfx, chan) \
+       _add_switch(codec, nid, pfx, chan, 1)
+#define add_in_mono_volume(codec, nid, pfx, chan) \
+       _add_volume(codec, nid, pfx, chan, 1)
+
+
+/*
+ * CA0132 specific
+ */
+
+struct ca0132_spec {
+       struct auto_pin_cfg autocfg;
+       struct hda_multi_out multiout;
+       hda_nid_t out_pins[AUTO_CFG_MAX_OUTS];
+       hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
+       hda_nid_t hp_dac;
+       hda_nid_t input_pins[AUTO_PIN_LAST];
+       hda_nid_t adcs[AUTO_PIN_LAST];
+       hda_nid_t dig_out;
+       hda_nid_t dig_in;
+       unsigned int num_inputs;
+       long curr_hp_switch;
+       long curr_hp_volume[2];
+       long curr_speaker_switch;
+       struct mutex chipio_mutex;
+       const char *input_labels[AUTO_PIN_LAST];
+       struct hda_pcm pcm_rec[2]; /* PCM information */
+};
+
+/* Chip access helper function */
+static int chipio_send(struct hda_codec *codec,
+                      unsigned int reg,
+                      unsigned int data)
+{
+       unsigned int res;
+       int retry = 50;
+
+       /* send bits of data specified by reg */
+       do {
+               res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
+                                        reg, data);
+               if (res == VENDOR_STATUS_CHIPIO_OK)
+                       return 0;
+       } while (--retry);
+       return -EIO;
+}
+
+/*
+ * Write chip address through the vendor widget -- NOT protected by the Mutex!
+ */
+static int chipio_write_address(struct hda_codec *codec,
+                               unsigned int chip_addx)
+{
+       int res;
+
+       /* send low 16 bits of the address */
+       res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_LOW,
+                         chip_addx & 0xffff);
+
+       if (res != -EIO) {
+               /* send high 16 bits of the address */
+               res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_HIGH,
+                                 chip_addx >> 16);
+       }
+
+       return res;
+}
+
+/*
+ * Write data through the vendor widget -- NOT protected by the Mutex!
+ */
+
+static int chipio_write_data(struct hda_codec *codec, unsigned int data)
+{
+       int res;
+
+       /* send low 16 bits of the data */
+       res = chipio_send(codec, VENDOR_CHIPIO_DATA_LOW, data & 0xffff);
+
+       if (res != -EIO) {
+               /* send high 16 bits of the data */
+               res = chipio_send(codec, VENDOR_CHIPIO_DATA_HIGH,
+                                 data >> 16);
+       }
+
+       return res;
+}
+
+/*
+ * Read data through the vendor widget -- NOT protected by the Mutex!
+ */
+static int chipio_read_data(struct hda_codec *codec, unsigned int *data)
+{
+       int res;
+
+       /* post read */
+       res = chipio_send(codec, VENDOR_CHIPIO_HIC_POST_READ, 0);
+
+       if (res != -EIO) {
+               /* read status */
+               res = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
+       }
+
+       if (res != -EIO) {
+               /* read data */
+               *data = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
+                                          VENDOR_CHIPIO_HIC_READ_DATA,
+                                          0);
+       }
+
+       return res;
+}
+
+/*
+ * Write given value to the given address through the chip I/O widget.
+ * protected by the Mutex
+ */
+static int chipio_write(struct hda_codec *codec,
+               unsigned int chip_addx, const unsigned int data)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int err;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       /* write the address, and if successful proceed to write data */
+       err = chipio_write_address(codec, chip_addx);
+       if (err < 0)
+               goto exit;
+
+       err = chipio_write_data(codec, data);
+       if (err < 0)
+               goto exit;
+
+exit:
+       mutex_unlock(&spec->chipio_mutex);
+       return err;
+}
+
+/*
+ * Read the given address through the chip I/O widget
+ * protected by the Mutex
+ */
+static int chipio_read(struct hda_codec *codec,
+               unsigned int chip_addx, unsigned int *data)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int err;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       /* write the address, and if successful proceed to write data */
+       err = chipio_write_address(codec, chip_addx);
+       if (err < 0)
+               goto exit;
+
+       err = chipio_read_data(codec, data);
+       if (err < 0)
+               goto exit;
+
+exit:
+       mutex_unlock(&spec->chipio_mutex);
+       return err;
+}
+
+/*
+ * PCM stuffs
+ */
+static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid,
+                                u32 stream_tag,
+                                int channel_id, int format)
+{
+       unsigned int oldval, newval;
+
+       if (!nid)
+               return;
+
+       snd_printdd("ca0132_setup_stream: "
+               "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
+               nid, stream_tag, channel_id, format);
+
+       /* update the format-id if changed */
+       oldval = snd_hda_codec_read(codec, nid, 0,
+                                   AC_VERB_GET_STREAM_FORMAT,
+                                   0);
+       if (oldval != format) {
+               msleep(20);
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_STREAM_FORMAT,
+                                   format);
+       }
+
+       oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
+       newval = (stream_tag << 4) | channel_id;
+       if (oldval != newval) {
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_CHANNEL_STREAMID,
+                                   newval);
+       }
+}
+
+static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
+{
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+}
+
+/*
+ * PCM callbacks
+ */
+static int ca0132_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 ca0132_spec *spec = codec->spec;
+
+       ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
+
+       return 0;
+}
+
+static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       ca0132_cleanup_stream(codec, spec->dacs[0]);
+
+       return 0;
+}
+
+/*
+ * Digital out
+ */
+static int ca0132_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 ca0132_spec *spec = codec->spec;
+
+       ca0132_setup_stream(codec, spec->dig_out, stream_tag, 0, format);
+
+       return 0;
+}
+
+static int ca0132_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       ca0132_cleanup_stream(codec, spec->dig_out);
+
+       return 0;
+}
+
+/*
+ * Analog capture
+ */
+static int ca0132_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 ca0132_spec *spec = codec->spec;
+
+       ca0132_setup_stream(codec, spec->adcs[substream->number],
+                            stream_tag, 0, format);
+
+       return 0;
+}
+
+static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       ca0132_cleanup_stream(codec, spec->adcs[substream->number]);
+
+       return 0;
+}
+
+/*
+ * Digital capture
+ */
+static int ca0132_dig_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 ca0132_spec *spec = codec->spec;
+
+       ca0132_setup_stream(codec, spec->dig_in, stream_tag, 0, format);
+
+       return 0;
+}
+
+static int ca0132_dig_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       ca0132_cleanup_stream(codec, spec->dig_in);
+
+       return 0;
+}
+
+/*
+ */
+static struct hda_pcm_stream ca0132_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .ops = {
+               .prepare = ca0132_playback_pcm_prepare,
+               .cleanup = ca0132_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream ca0132_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .ops = {
+               .prepare = ca0132_capture_pcm_prepare,
+               .cleanup = ca0132_capture_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream ca0132_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .ops = {
+               .prepare = ca0132_dig_playback_pcm_prepare,
+               .cleanup = ca0132_dig_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream ca0132_pcm_digital_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .ops = {
+               .prepare = ca0132_dig_capture_pcm_prepare,
+               .cleanup = ca0132_dig_capture_pcm_cleanup
+       },
+};
+
+static int ca0132_build_pcms(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct hda_pcm *info = spec->pcm_rec;
+
+       codec->pcm_info = info;
+       codec->num_pcms = 0;
+
+       info->name = "CA0132 Analog";
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback;
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+               spec->multiout.max_channels;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
+       codec->num_pcms++;
+
+       if (!spec->dig_out && !spec->dig_in)
+               return 0;
+
+       info++;
+       info->name = "CA0132 Digital";
+       info->pcm_type = HDA_PCM_TYPE_SPDIF;
+       if (spec->dig_out) {
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+                       ca0132_pcm_digital_playback;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
+       }
+       if (spec->dig_in) {
+               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                       ca0132_pcm_digital_capture;
+               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
+       }
+       codec->num_pcms++;
+
+       return 0;
+}
+
+#define REG_CODEC_MUTE         0x18b014
+#define REG_CODEC_HP_VOL_L     0x18b070
+#define REG_CODEC_HP_VOL_R     0x18b074
+
+static int ca0132_hp_switch_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       long *valp = ucontrol->value.integer.value;
+
+       *valp = spec->curr_hp_switch;
+       return 0;
+}
+
+static int ca0132_hp_switch_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       long *valp = ucontrol->value.integer.value;
+       unsigned int data;
+       int err;
+
+       /* any change? */
+       if (spec->curr_hp_switch == *valp)
+               return 0;
+
+       snd_hda_power_up(codec);
+
+       err = chipio_read(codec, REG_CODEC_MUTE, &data);
+       if (err < 0)
+               return err;
+
+       /* *valp 0 is mute, 1 is unmute */
+       data = (data & 0x7f) | (*valp ? 0 : 0x80);
+       chipio_write(codec, REG_CODEC_MUTE, data);
+       if (err < 0)
+               return err;
+
+       spec->curr_hp_switch = *valp;
+
+       snd_hda_power_down(codec);
+       return 1;
+}
+
+static int ca0132_speaker_switch_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       long *valp = ucontrol->value.integer.value;
+
+       *valp = spec->curr_speaker_switch;
+       return 0;
+}
+
+static int ca0132_speaker_switch_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       long *valp = ucontrol->value.integer.value;
+       unsigned int data;
+       int err;
+
+       /* any change? */
+       if (spec->curr_speaker_switch == *valp)
+               return 0;
+
+       snd_hda_power_up(codec);
+
+       err = chipio_read(codec, REG_CODEC_MUTE, &data);
+       if (err < 0)
+               return err;
+
+       /* *valp 0 is mute, 1 is unmute */
+       data = (data & 0xef) | (*valp ? 0 : 0x10);
+       chipio_write(codec, REG_CODEC_MUTE, data);
+       if (err < 0)
+               return err;
+
+       spec->curr_speaker_switch = *valp;
+
+       snd_hda_power_down(codec);
+       return 1;
+}
+
+static int ca0132_hp_volume_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       long *valp = ucontrol->value.integer.value;
+
+       *valp++ = spec->curr_hp_volume[0];
+       *valp = spec->curr_hp_volume[1];
+       return 0;
+}
+
+static int ca0132_hp_volume_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       long *valp = ucontrol->value.integer.value;
+       long left_vol, right_vol;
+       unsigned int data;
+       int val;
+       int err;
+
+       left_vol = *valp++;
+       right_vol = *valp;
+
+       /* any change? */
+       if ((spec->curr_hp_volume[0] == left_vol) &&
+               (spec->curr_hp_volume[1] == right_vol))
+               return 0;
+
+       snd_hda_power_up(codec);
+
+       err = chipio_read(codec, REG_CODEC_HP_VOL_L, &data);
+       if (err < 0)
+               return err;
+
+       val = 31 - left_vol;
+       data = (data & 0xe0) | val;
+       chipio_write(codec, REG_CODEC_HP_VOL_L, data);
+       if (err < 0)
+               return err;
+
+       val = 31 - right_vol;
+       data = (data & 0xe0) | val;
+       chipio_write(codec, REG_CODEC_HP_VOL_R, data);
+       if (err < 0)
+               return err;
+
+       spec->curr_hp_volume[0] = left_vol;
+       spec->curr_hp_volume[1] = right_vol;
+
+       snd_hda_power_down(codec);
+       return 1;
+}
+
+static int add_hp_switch(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("Headphone Playback Switch",
+                                    nid, 1, 0, HDA_OUTPUT);
+       knew.get = ca0132_hp_switch_get;
+       knew.put = ca0132_hp_switch_put;
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
+}
+
+static int add_hp_volume(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_VOLUME_MONO("Headphone Playback Volume",
+                                      nid, 3, 0, HDA_OUTPUT);
+       knew.get = ca0132_hp_volume_get;
+       knew.put = ca0132_hp_volume_put;
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
+}
+
+static int add_speaker_switch(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("Speaker Playback Switch",
+                                    nid, 1, 0, HDA_OUTPUT);
+       knew.get = ca0132_speaker_switch_get;
+       knew.put = ca0132_speaker_switch_put;
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
+}
+
+static void ca0132_fix_hp_caps(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int caps;
+
+       /* set mute-capable, 1db step, 32 steps, ofs 6 */
+       caps = 0x80031f06;
+       snd_hda_override_amp_caps(codec, cfg->hp_pins[0], HDA_OUTPUT, caps);
+}
+
+static int ca0132_build_controls(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, err;
+
+       if (spec->multiout.num_dacs) {
+               err = add_speaker_switch(codec, spec->out_pins[0]);
+               if (err < 0)
+                       return err;
+       }
+
+       if (cfg->hp_outs) {
+               ca0132_fix_hp_caps(codec);
+               err = add_hp_switch(codec, cfg->hp_pins[0]);
+               if (err < 0)
+                       return err;
+               err = add_hp_volume(codec, cfg->hp_pins[0]);
+               if (err < 0)
+                       return err;
+       }
+
+       for (i = 0; i < spec->num_inputs; i++) {
+               const char *label = spec->input_labels[i];
+
+               err = add_in_switch(codec, spec->adcs[i], label);
+               if (err < 0)
+                       return err;
+               err = add_in_volume(codec, spec->adcs[i], label);
+               if (err < 0)
+                       return err;
+               if (cfg->inputs[i].type == AUTO_PIN_MIC) {
+                       /* add Mic-Boost */
+                       err = add_in_mono_volume(codec, spec->input_pins[i],
+                                                "Mic Boost", 1);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       if (spec->dig_out) {
+               err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
+                                                   spec->dig_out);
+               if (err < 0)
+                       return err;
+               err = add_out_volume(codec, spec->dig_out, "IEC958");
+               if (err < 0)
+                       return err;
+       }
+
+       if (spec->dig_in) {
+               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
+               if (err < 0)
+                       return err;
+               err = add_in_volume(codec, spec->dig_in, "IEC958");
+       }
+       return 0;
+}
+
+
+static void ca0132_set_ct_ext(struct hda_codec *codec, int enable)
+{
+       /* Set Creative extension */
+       snd_printdd("SET CREATIVE EXTENSION\n");
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE,
+                           enable);
+       msleep(20);
+}
+
+
+static void ca0132_config(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       /* line-outs */
+       cfg->line_outs = 1;
+       cfg->line_out_pins[0] = 0x0b; /* front */
+       cfg->line_out_type = AUTO_PIN_LINE_OUT;
+
+       spec->dacs[0] = 0x02;
+       spec->out_pins[0] = 0x0b;
+       spec->multiout.dac_nids = spec->dacs;
+       spec->multiout.num_dacs = 1;
+       spec->multiout.max_channels = 2;
+
+       /* headphone */
+       cfg->hp_outs = 1;
+       cfg->hp_pins[0] = 0x0f;
+
+       spec->hp_dac = 0;
+       spec->multiout.hp_nid = 0;
+
+       /* inputs */
+       cfg->num_inputs = 2;  /* Mic-in and line-in */
+       cfg->inputs[0].pin = 0x12;
+       cfg->inputs[0].type = AUTO_PIN_MIC;
+       cfg->inputs[1].pin = 0x11;
+       cfg->inputs[1].type = AUTO_PIN_LINE_IN;
+
+       /* Mic-in */
+       spec->input_pins[0] = 0x12;
+       spec->input_labels[0] = "Mic-In";
+       spec->adcs[0] = 0x07;
+
+       /* Line-In */
+       spec->input_pins[1] = 0x11;
+       spec->input_labels[1] = "Line-In";
+       spec->adcs[1] = 0x08;
+       spec->num_inputs = 2;
+}
+
+static void ca0132_init_chip(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_init(&spec->chipio_mutex);
+}
+
+static void ca0132_exit_chip(struct hda_codec *codec)
+{
+       /* put any chip cleanup stuffs here. */
+}
+
+static int ca0132_init(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < spec->multiout.num_dacs; i++) {
+               init_output(codec, spec->out_pins[i],
+                           spec->multiout.dac_nids[i]);
+       }
+       init_output(codec, cfg->hp_pins[0], spec->hp_dac);
+       init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
+
+       for (i = 0; i < spec->num_inputs; i++)
+               init_input(codec, spec->input_pins[i], spec->adcs[i]);
+
+       init_input(codec, cfg->dig_in_pin, spec->dig_in);
+
+       ca0132_set_ct_ext(codec, 1);
+
+       return 0;
+}
+
+
+static void ca0132_free(struct hda_codec *codec)
+{
+       ca0132_set_ct_ext(codec, 0);
+       ca0132_exit_chip(codec);
+       kfree(codec->spec);
+}
+
+static struct hda_codec_ops ca0132_patch_ops = {
+       .build_controls = ca0132_build_controls,
+       .build_pcms = ca0132_build_pcms,
+       .init = ca0132_init,
+       .free = ca0132_free,
+};
+
+
+
+static int patch_ca0132(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec;
+
+       snd_printdd("patch_ca0132\n");
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+
+       ca0132_init_chip(codec);
+
+       ca0132_config(codec);
+
+       codec->patch_ops = ca0132_patch_ops;
+
+       return 0;
+}
+
+/*
+ * patch entries
+ */
+static struct hda_codec_preset snd_hda_preset_ca0132[] = {
+       { .id = 0x11020011, .name = "CA0132",     .patch = patch_ca0132 },
+       {} /* terminator */
+};
+
+MODULE_ALIAS("snd-hda-codec-id:11020011");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Creative CA0132, CA0132 HD-audio codec");
+
+static struct hda_codec_preset_list ca0132_list = {
+       .preset = snd_hda_preset_ca0132,
+       .owner = THIS_MODULE,
+};
+
+static int __init patch_ca0132_init(void)
+{
+       return snd_hda_add_codec_preset(&ca0132_list);
+}
+
+static void __exit patch_ca0132_exit(void)
+{
+       snd_hda_delete_codec_preset(&ca0132_list);
+}
+
+module_init(patch_ca0132_init)
+module_exit(patch_ca0132_exit)
index 26a1521..7f93739 100644 (file)
@@ -346,21 +346,15 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
 
        nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++) {
-               hda_nid_t pins[2];
                unsigned int type;
-               int j, nums;
+               int idx;
                type = get_wcaps_type(get_wcaps(codec, nid));
                if (type != AC_WID_AUD_IN)
                        continue;
-               nums = snd_hda_get_connections(codec, nid, pins,
-                                              ARRAY_SIZE(pins));
-               if (nums <= 0)
-                       continue;
-               for (j = 0; j < nums; j++) {
-                       if (pins[j] == pin) {
-                               *idxp = j;
-                               return nid;
-                       }
+               idx = snd_hda_get_conn_index(codec, nid, pin, 0);
+               if (idx >= 0) {
+                       *idxp = idx;
+                       return nid;
                }
        }
        return 0;
@@ -821,7 +815,8 @@ static int build_digital_output(struct hda_codec *codec)
        if (!spec->multiout.dig_out_nid)
                return 0;
 
-       err = snd_hda_create_spdif_out_ctls(codec, 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);
index ab3308d..cd2cf5e 100644 (file)
@@ -327,7 +327,9 @@ static int cmi9880_build_controls(struct hda_codec *codec)
                        return err;
        }
        if (spec->multiout.dig_out_nid) {
-               err = snd_hda_create_spdif_out_ctls(codec, 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,
@@ -396,12 +398,11 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi
 {
        struct cmi_spec *spec = codec->spec;
        hda_nid_t nid;
-       int i, j, k, len;
+       int i, j, k;
 
        /* clear the table, only one c-media dac assumed here */
        memset(spec->multi_init, 0, sizeof(spec->multi_init));
        for (j = 0, i = 0; i < cfg->line_outs; i++) {
-               hda_nid_t conn[4];
                nid = cfg->line_out_pins[i];
                /* set as output */
                spec->multi_init[j].nid = nid;
@@ -414,12 +415,10 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi
                        spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL;
                        spec->multi_init[j].param = 0;
                        /* find the index in connect list */
-                       len = snd_hda_get_connections(codec, nid, conn, 4);
-                       for (k = 0; k < len; k++)
-                               if (conn[k] == spec->dac_nids[i]) {
-                                       spec->multi_init[j].param = k;
-                                       break;
-                               }
+                       k = snd_hda_get_conn_index(codec, nid,
+                                                  spec->dac_nids[i], 0);
+                       if (k >= 0)
+                               spec->multi_init[j].param = k;
                        j++;
                }
        }
index 7bbc5f2..884f67b 100644 (file)
@@ -155,6 +155,10 @@ struct conexant_spec {
        unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
 
        unsigned int beep_amp;
+
+       /* extra EAPD pins */
+       unsigned int num_eapds;
+       hda_nid_t eapds[4];
 };
 
 static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -510,6 +514,7 @@ static int conexant_build_controls(struct hda_codec *codec)
        }
        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;
@@ -1123,10 +1128,8 @@ static int patch_cxt5045(struct hda_codec *codec)
        board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
                                                  cxt5045_models,
                                                  cxt5045_cfg_tbl);
-#if 0 /* use the old method just for safety */
        if (board_config < 0)
-               board_config = CXT5045_AUTO;
-#endif
+               board_config = CXT5045_AUTO; /* model=auto as default */
        if (board_config == CXT5045_AUTO)
                return patch_conexant_auto(codec);
 
@@ -1564,10 +1567,8 @@ static int patch_cxt5047(struct hda_codec *codec)
        board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
                                                  cxt5047_models,
                                                  cxt5047_cfg_tbl);
-#if 0 /* not enabled as default, as BIOS often broken for this codec */
        if (board_config < 0)
-               board_config = CXT5047_AUTO;
-#endif
+               board_config = CXT5047_AUTO; /* model=auto as default */
        if (board_config == CXT5047_AUTO)
                return patch_conexant_auto(codec);
 
@@ -1993,10 +1994,8 @@ static int patch_cxt5051(struct hda_codec *codec)
        board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
                                                  cxt5051_models,
                                                  cxt5051_cfg_tbl);
-#if 0 /* use the old method just for safety */
        if (board_config < 0)
-               board_config = CXT5051_AUTO;
-#endif
+               board_config = CXT5051_AUTO; /* model=auto as default */
        if (board_config == CXT5051_AUTO)
                return patch_conexant_auto(codec);
 
@@ -3114,10 +3113,8 @@ static int patch_cxt5066(struct hda_codec *codec)
 
        board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
                                                  cxt5066_models, cxt5066_cfg_tbl);
-#if 0 /* use the old method just for safety */
        if (board_config < 0)
-               board_config = CXT5066_AUTO;
-#endif
+               board_config = CXT5066_AUTO; /* model=auto as default */
        if (board_config == CXT5066_AUTO)
                return patch_conexant_auto(codec);
 
@@ -3308,19 +3305,8 @@ static const struct hda_pcm_stream cx_auto_pcm_analog_capture = {
 
 static const hda_nid_t cx_auto_adc_nids[] = { 0x14 };
 
-/* get the connection index of @nid in the widget @mux */
-static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
-                               hda_nid_t nid)
-{
-       hda_nid_t conn[HDA_MAX_NUM_INPUTS];
-       int i, nums;
-
-       nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
-       for (i = 0; i < nums; i++)
-               if (conn[i] == nid)
-                       return i;
-       return -1;
-}
+#define get_connection_index(codec, mux, nid)\
+       snd_hda_get_conn_index(codec, mux, nid, 0)
 
 /* get an unassigned DAC from the given list.
  * Return the nid if found and reduce the DAC list, or return zero if
@@ -3919,6 +3905,38 @@ static void cx_auto_parse_beep(struct hda_codec *codec)
 #define cx_auto_parse_beep(codec)
 #endif
 
+static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+       int i;
+       for (i = 0; i < nums; i++)
+               if (list[i] == nid)
+                       return true;
+       return false;
+}
+
+/* parse extra-EAPD that aren't assigned to any pins */
+static void cx_auto_parse_eapd(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid, end_nid;
+
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++) {
+               if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+                       continue;
+               if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
+                       continue;
+               if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) ||
+                   found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) ||
+                   found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs))
+                       continue;
+               spec->eapds[spec->num_eapds++] = nid;
+               if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
+                       break;
+       }
+}
+
 static int cx_auto_parse_auto_config(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
@@ -3932,6 +3950,7 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec)
        cx_auto_parse_input(codec);
        cx_auto_parse_digital(codec);
        cx_auto_parse_beep(codec);
+       cx_auto_parse_eapd(codec);
        return 0;
 }
 
@@ -4019,6 +4038,8 @@ static void cx_auto_init_output(struct hda_codec *codec)
                }
        }
        cx_auto_update_speakers(codec);
+       /* turn on/off extra EAPDs, too */
+       cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
 }
 
 static void cx_auto_init_input(struct hda_codec *codec)
index bd0ae69..19cb72d 100644 (file)
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 
 /*
  * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
- * could support two independent pipes, each of them can be connected to one or
+ * could support N independent pipes, each of them can be connected to one or
  * more ports (DVI, HDMI or DisplayPort).
  *
  * The HDA correspondence of pipes/ports are converter/pin nodes.
@@ -51,30 +51,33 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 #define MAX_HDMI_CVTS  4
 #define MAX_HDMI_PINS  4
 
-struct hdmi_spec {
-       int num_cvts;
-       int num_pins;
-       hda_nid_t cvt[MAX_HDMI_CVTS+1];  /* audio sources */
-       hda_nid_t pin[MAX_HDMI_PINS+1];  /* audio sinks */
+struct hdmi_spec_per_cvt {
+       hda_nid_t cvt_nid;
+       int assigned;
+       unsigned int channels_min;
+       unsigned int channels_max;
+       u32 rates;
+       u64 formats;
+       unsigned int maxbps;
+};
 
-       /*
-        * source connection for each pin
-        */
-       hda_nid_t pin_cvt[MAX_HDMI_PINS+1];
+struct hdmi_spec_per_pin {
+       hda_nid_t pin_nid;
+       int num_mux_nids;
+       hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+       struct hdmi_eld sink_eld;
+};
 
-       /*
-        * HDMI sink attached to each pin
-        */
-       struct hdmi_eld sink_eld[MAX_HDMI_PINS];
+struct hdmi_spec {
+       int num_cvts;
+       struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
 
-       /*
-        * export one pcm per pipe
-        */
-       struct hda_pcm  pcm_rec[MAX_HDMI_CVTS];
-       struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS];
+       int num_pins;
+       struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
+       struct hda_pcm pcm_rec[MAX_HDMI_PINS];
 
        /*
-        * ati/nvhdmi specific
+        * Non-generic ATI/NVIDIA specific
         */
        struct hda_multi_out multiout;
        const struct hda_pcm_stream *pcm_playback;
@@ -284,15 +287,40 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
  * HDMI routines
  */
 
-static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
+static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid)
 {
-       int i;
+       int pin_idx;
 
-       for (i = 0; nids[i]; i++)
-               if (nids[i] == nid)
-                       return i;
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
+               if (spec->pins[pin_idx].pin_nid == pin_nid)
+                       return pin_idx;
 
-       snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid);
+       snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid);
+       return -EINVAL;
+}
+
+static int hinfo_to_pin_index(struct hdmi_spec *spec,
+                             struct hda_pcm_stream *hinfo)
+{
+       int pin_idx;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
+               if (&spec->pcm_rec[pin_idx].stream[0] == hinfo)
+                       return pin_idx;
+
+       snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo);
+       return -EINVAL;
+}
+
+static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
+{
+       int cvt_idx;
+
+       for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
+               if (spec->cvts[cvt_idx].cvt_nid == cvt_nid)
+                       return cvt_idx;
+
+       snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid);
        return -EINVAL;
 }
 
@@ -326,28 +354,28 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
        snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
 }
 
-static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid)
+static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 {
        /* Unmute */
        if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
                snd_hda_codec_write(codec, pin_nid, 0,
                                AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-       /* Enable pin out */
+       /* Disable pin out until stream is active*/
        snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
 }
 
-static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid)
+static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
 {
-       return 1 + snd_hda_codec_read(codec, nid, 0,
+       return 1 + snd_hda_codec_read(codec, cvt_nid, 0,
                                        AC_VERB_GET_CVT_CHAN_COUNT, 0);
 }
 
 static void hdmi_set_channel_count(struct hda_codec *codec,
-                                  hda_nid_t nid, int chs)
+                                  hda_nid_t cvt_nid, int chs)
 {
-       if (chs != hdmi_get_channel_count(codec, nid))
-               snd_hda_codec_write(codec, nid, 0,
+       if (chs != hdmi_get_channel_count(codec, cvt_nid))
+               snd_hda_codec_write(codec, cvt_nid, 0,
                                    AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
 }
 
@@ -384,11 +412,8 @@ static void init_channel_allocations(void)
  *
  * TODO: it could select the wrong CA from multiple candidates.
 */
-static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
-                                  int channels)
+static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels)
 {
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_eld *eld;
        int i;
        int ca = 0;
        int spk_mask = 0;
@@ -400,19 +425,6 @@ static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
        if (channels <= 2)
                return 0;
 
-       i = hda_node_index(spec->pin_cvt, nid);
-       if (i < 0)
-               return 0;
-       eld = &spec->sink_eld[i];
-
-       /*
-        * HDMI sink's ELD info cannot always be retrieved for now, e.g.
-        * in console or for audio devices. Assume the highest speakers
-        * configuration, to _not_ prohibit multi-channel audio playback.
-        */
-       if (!eld->spk_alloc)
-               eld->spk_alloc = 0xffff;
-
        /*
         * expand ELD's speaker allocation mask
         *
@@ -608,67 +620,63 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
        return true;
 }
 
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
                                        struct snd_pcm_substream *substream)
 {
        struct hdmi_spec *spec = codec->spec;
-       hda_nid_t pin_nid;
+       struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+       hda_nid_t pin_nid = per_pin->pin_nid;
        int channels = substream->runtime->channels;
+       struct hdmi_eld *eld;
        int ca;
-       int i;
        union audio_infoframe ai;
 
-       ca = hdmi_channel_allocation(codec, nid, channels);
-
-       for (i = 0; i < spec->num_pins; i++) {
-               if (spec->pin_cvt[i] != nid)
-                       continue;
-               if (!spec->sink_eld[i].monitor_present)
-                       continue;
+       eld = &spec->pins[pin_idx].sink_eld;
+       if (!eld->monitor_present)
+               return;
 
-               pin_nid = spec->pin[i];
-
-               memset(&ai, 0, sizeof(ai));
-               if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
-                       struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
-
-                       hdmi_ai->type           = 0x84;
-                       hdmi_ai->ver            = 0x01;
-                       hdmi_ai->len            = 0x0a;
-                       hdmi_ai->CC02_CT47      = channels - 1;
-                       hdmi_ai->CA             = ca;
-                       hdmi_checksum_audio_infoframe(hdmi_ai);
-               } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
-                       struct dp_audio_infoframe *dp_ai = &ai.dp;
-
-                       dp_ai->type             = 0x84;
-                       dp_ai->len              = 0x1b;
-                       dp_ai->ver              = 0x11 << 2;
-                       dp_ai->CC02_CT47        = channels - 1;
-                       dp_ai->CA               = ca;
-               } else {
-                       snd_printd("HDMI: unknown connection type at pin %d\n",
-                                  pin_nid);
-                       continue;
-               }
+       ca = hdmi_channel_allocation(eld, channels);
+
+       memset(&ai, 0, sizeof(ai));
+       if (eld->conn_type == 0) { /* HDMI */
+               struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
+
+               hdmi_ai->type           = 0x84;
+               hdmi_ai->ver            = 0x01;
+               hdmi_ai->len            = 0x0a;
+               hdmi_ai->CC02_CT47      = channels - 1;
+               hdmi_ai->CA             = ca;
+               hdmi_checksum_audio_infoframe(hdmi_ai);
+       } else if (eld->conn_type == 1) { /* DisplayPort */
+               struct dp_audio_infoframe *dp_ai = &ai.dp;
+
+               dp_ai->type             = 0x84;
+               dp_ai->len              = 0x1b;
+               dp_ai->ver              = 0x11 << 2;
+               dp_ai->CC02_CT47        = channels - 1;
+               dp_ai->CA               = ca;
+       } else {
+               snd_printd("HDMI: unknown connection type at pin %d\n",
+                           pin_nid);
+               return;
+       }
 
-               /*
-                * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
-                * sizeof(*dp_ai) to avoid partial match/update problems when
-                * the user switches between HDMI/DP monitors.
-                */
-               if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
-                                            sizeof(ai))) {
-                       snd_printdd("hdmi_setup_audio_infoframe: "
-                                   "cvt=%d pin=%d channels=%d\n",
-                                   nid, pin_nid,
-                                   channels);
-                       hdmi_setup_channel_mapping(codec, pin_nid, ca);
-                       hdmi_stop_infoframe_trans(codec, pin_nid);
-                       hdmi_fill_audio_infoframe(codec, pin_nid,
-                                                 ai.bytes, sizeof(ai));
-                       hdmi_start_infoframe_trans(codec, pin_nid);
-               }
+       /*
+        * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
+        * sizeof(*dp_ai) to avoid partial match/update problems when
+        * the user switches between HDMI/DP monitors.
+        */
+       if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
+                                       sizeof(ai))) {
+               snd_printdd("hdmi_setup_audio_infoframe: "
+                           "pin=%d channels=%d\n",
+                           pin_nid,
+                           channels);
+               hdmi_setup_channel_mapping(codec, pin_nid, ca);
+               hdmi_stop_infoframe_trans(codec, pin_nid);
+               hdmi_fill_audio_infoframe(codec, pin_nid,
+                                           ai.bytes, sizeof(ai));
+               hdmi_start_infoframe_trans(codec, pin_nid);
        }
 }
 
@@ -686,17 +694,27 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
        int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT;
        int pd = !!(res & AC_UNSOL_RES_PD);
        int eldv = !!(res & AC_UNSOL_RES_ELDV);
-       int index;
+       int pin_idx;
+       struct hdmi_eld *eld;
 
        printk(KERN_INFO
-               "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
-               pin_nid, pd, eldv);
+               "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+               codec->addr, pin_nid, pd, eldv);
 
-       index = hda_node_index(spec->pin, pin_nid);
-       if (index < 0)
+       pin_idx = pin_nid_to_pin_index(spec, pin_nid);
+       if (pin_idx < 0)
                return;
+       eld = &spec->pins[pin_idx].sink_eld;
 
-       hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]);
+       hdmi_present_sense(codec, pin_nid, eld);
+
+       /*
+        * HDMI sink's ELD info cannot always be retrieved for now, e.g.
+        * in console or for audio devices. Assume the highest speakers
+        * configuration, to _not_ prohibit multi-channel audio playback.
+        */
+       if (!eld->spk_alloc)
+               eld->spk_alloc = 0xffff;
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -707,7 +725,8 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
        int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
 
        printk(KERN_INFO
-               "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+               "HDMI CP event: CODEC=%d PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+               codec->addr,
                tag,
                subtag,
                cp_state,
@@ -727,7 +746,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
        int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
        int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
 
-       if (hda_node_index(spec->pin, tag) < 0) {
+       if (pin_nid_to_pin_index(spec, tag) < 0) {
                snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
                return;
        }
@@ -746,21 +765,14 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
 #define is_hbr_format(format) \
        ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
 
-static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
-                             u32 stream_tag, int format)
+static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+                             hda_nid_t pin_nid, u32 stream_tag, int format)
 {
-       struct hdmi_spec *spec = codec->spec;
        int pinctl;
        int new_pinctl = 0;
-       int i;
-
-       for (i = 0; i < spec->num_pins; i++) {
-               if (spec->pin_cvt[i] != nid)
-                       continue;
-               if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR))
-                       continue;
 
-               pinctl = snd_hda_codec_read(codec, spec->pin[i], 0,
+       if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
+               pinctl = snd_hda_codec_read(codec, pin_nid, 0,
                                            AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 
                new_pinctl = pinctl & ~AC_PINCTL_EPT;
@@ -771,22 +783,22 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 
                snd_printdd("hdmi_setup_stream: "
                            "NID=0x%x, %spinctl=0x%x\n",
-                           spec->pin[i],
+                           pin_nid,
                            pinctl == new_pinctl ? "" : "new-",
                            new_pinctl);
 
                if (pinctl != new_pinctl)
-                       snd_hda_codec_write(codec, spec->pin[i], 0,
+                       snd_hda_codec_write(codec, pin_nid, 0,
                                            AC_VERB_SET_PIN_WIDGET_CONTROL,
                                            new_pinctl);
-       }
 
+       }
        if (is_hbr_format(format) && !new_pinctl) {
                snd_printdd("hdmi_setup_stream: HBR is not supported\n");
                return -EINVAL;
        }
 
-       snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+       snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
        return 0;
 }
 
@@ -798,37 +810,70 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                         struct snd_pcm_substream *substream)
 {
        struct hdmi_spec *spec = codec->spec;
-       struct hdmi_eld *eld;
-       struct hda_pcm_stream *codec_pars;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int idx;
+       int pin_idx, cvt_idx, mux_idx = 0;
+       struct hdmi_spec_per_pin *per_pin;
+       struct hdmi_eld *eld;
+       struct hdmi_spec_per_cvt *per_cvt = NULL;
+       int pinctl;
 
-       for (idx = 0; idx < spec->num_cvts; idx++)
-               if (hinfo->nid == spec->cvt[idx])
-                       break;
-       if (snd_BUG_ON(idx >= spec->num_cvts) ||
-           snd_BUG_ON(idx >= spec->num_pins))
+       /* Validate hinfo */
+       pin_idx = hinfo_to_pin_index(spec, hinfo);
+       if (snd_BUG_ON(pin_idx < 0))
                return -EINVAL;
+       per_pin = &spec->pins[pin_idx];
+       eld = &per_pin->sink_eld;
 
-       /* save the PCM info the codec provides */
-       codec_pars = &spec->codec_pcm_pars[idx];
-       if (!codec_pars->rates)
-               *codec_pars = *hinfo;
+       /* Dynamically assign converter to stream */
+       for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+               per_cvt = &spec->cvts[cvt_idx];
 
-       eld = &spec->sink_eld[idx];
-       if (!static_hdmi_pcm && eld->eld_valid && eld->sad_count > 0) {
-               hdmi_eld_update_pcm_info(eld, hinfo, codec_pars);
+               /* Must not already be assigned */
+               if (per_cvt->assigned)
+                       continue;
+               /* Must be in pin's mux's list of converters */
+               for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
+                       if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid)
+                               break;
+               /* Not in mux list */
+               if (mux_idx == per_pin->num_mux_nids)
+                       continue;
+               break;
+       }
+       /* No free converters */
+       if (cvt_idx == spec->num_cvts)
+               return -ENODEV;
+
+       /* Claim converter */
+       per_cvt->assigned = 1;
+       hinfo->nid = per_cvt->cvt_nid;
+
+       snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+                           AC_VERB_SET_CONNECT_SEL,
+                           mux_idx);
+       pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+                                   AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+       snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           pinctl | PIN_OUT);
+       snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
+
+       /* Initially set the converter's capabilities */
+       hinfo->channels_min = per_cvt->channels_min;
+       hinfo->channels_max = per_cvt->channels_max;
+       hinfo->rates = per_cvt->rates;
+       hinfo->formats = per_cvt->formats;
+       hinfo->maxbps = per_cvt->maxbps;
+
+       /* Restrict capabilities by ELD if this isn't disabled */
+       if (!static_hdmi_pcm && eld->eld_valid) {
+               snd_hdmi_eld_update_pcm_info(eld, hinfo);
                if (hinfo->channels_min > hinfo->channels_max ||
                    !hinfo->rates || !hinfo->formats)
                        return -ENODEV;
-       } else {
-               /* fallback to the codec default */
-               hinfo->channels_max = codec_pars->channels_max;
-               hinfo->rates = codec_pars->rates;
-               hinfo->formats = codec_pars->formats;
-               hinfo->maxbps = codec_pars->maxbps;
        }
-       /* store the updated parameters */
+
+       /* Store the updated parameters */
        runtime->hw.channels_min = hinfo->channels_min;
        runtime->hw.channels_max = hinfo->channels_max;
        runtime->hw.formats = hinfo->formats;
@@ -842,12 +887,11 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 /*
  * HDA/HDMI auto parsing
  */
-static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
+static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
 {
        struct hdmi_spec *spec = codec->spec;
-       hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
-       int conn_len, curr;
-       int index;
+       struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+       hda_nid_t pin_nid = per_pin->pin_nid;
 
        if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
                snd_printk(KERN_WARNING
@@ -857,19 +901,9 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
                return -EINVAL;
        }
 
-       conn_len = snd_hda_get_connections(codec, pin_nid, conn_list,
-                                          HDA_MAX_CONNECTIONS);
-       if (conn_len > 1)
-               curr = snd_hda_codec_read(codec, pin_nid, 0,
-                                         AC_VERB_GET_CONNECT_SEL, 0);
-       else
-               curr = 0;
-
-       index = hda_node_index(spec->pin, pin_nid);
-       if (index < 0)
-               return -EINVAL;
-
-       spec->pin_cvt[index] = conn_list[curr];
+       per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid,
+                                                       per_pin->mux_nids,
+                                                       HDA_MAX_CONNECTIONS);
 
        return 0;
 }
@@ -896,8 +930,8 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
                eld->eld_valid  = 0;
 
        printk(KERN_INFO
-               "HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
-               pin_nid, eld->monitor_present, eld->eld_valid);
+               "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+               codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
 
        if (eld->eld_valid)
                if (!snd_hdmi_get_eld(eld, codec, pin_nid))
@@ -909,47 +943,75 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 {
        struct hdmi_spec *spec = codec->spec;
+       unsigned int caps, config;
+       int pin_idx;
+       struct hdmi_spec_per_pin *per_pin;
+       struct hdmi_eld *eld;
        int err;
 
-       if (spec->num_pins >= MAX_HDMI_PINS) {
-               snd_printk(KERN_WARNING
-                          "HDMI: no space for pin %d\n", pin_nid);
+       caps = snd_hda_param_read(codec, pin_nid, AC_PAR_PIN_CAP);
+       if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
+               return 0;
+
+       config = snd_hda_codec_read(codec, pin_nid, 0,
+                               AC_VERB_GET_CONFIG_DEFAULT, 0);
+       if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
+               return 0;
+
+       if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS))
                return -E2BIG;
-       }
+
+       pin_idx = spec->num_pins;
+       per_pin = &spec->pins[pin_idx];
+       eld = &per_pin->sink_eld;
+
+       per_pin->pin_nid = pin_nid;
 
        err = snd_hda_input_jack_add(codec, pin_nid,
                                     SND_JACK_VIDEOOUT, NULL);
        if (err < 0)
                return err;
 
-       hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
+       err = hdmi_read_pin_conn(codec, pin_idx);
+       if (err < 0)
+               return err;
 
-       spec->pin[spec->num_pins] = pin_nid;
        spec->num_pins++;
 
-       return hdmi_read_pin_conn(codec, pin_nid);
+       hdmi_present_sense(codec, pin_nid, eld);
+
+       return 0;
 }
 
-static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
+static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
 {
-       int i, found_pin = 0;
        struct hdmi_spec *spec = codec->spec;
-
-       for (i = 0; i < spec->num_pins; i++)
-               if (nid == spec->pin_cvt[i]) {
-                       found_pin = 1;
-                       break;
-               }
-
-       if (!found_pin) {
-               snd_printdd("HDMI: Skipping node %d (no connection)\n", nid);
-               return -EINVAL;
-       }
+       int cvt_idx;
+       struct hdmi_spec_per_cvt *per_cvt;
+       unsigned int chans;
+       int err;
 
        if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
                return -E2BIG;
 
-       spec->cvt[spec->num_cvts] = nid;
+       chans = get_wcaps(codec, cvt_nid);
+       chans = get_wcaps_channels(chans);
+
+       cvt_idx = spec->num_cvts;
+       per_cvt = &spec->cvts[cvt_idx];
+
+       per_cvt->cvt_nid = cvt_nid;
+       per_cvt->channels_min = 2;
+       if (chans <= 16)
+               per_cvt->channels_max = chans;
+
+       err = snd_hda_query_supported_pcm(codec, cvt_nid,
+                                         &per_cvt->rates,
+                                         &per_cvt->formats,
+                                         &per_cvt->maxbps);
+       if (err < 0)
+               return err;
+
        spec->num_cvts++;
 
        return 0;
@@ -959,8 +1021,6 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 {
        hda_nid_t nid;
        int i, nodes;
-       int num_tmp_cvts = 0;
-       hda_nid_t tmp_cvt[MAX_HDMI_CVTS];
 
        nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
        if (!nid || nodes < 0) {
@@ -971,7 +1031,6 @@ static int hdmi_parse_codec(struct hda_codec *codec)
        for (i = 0; i < nodes; i++, nid++) {
                unsigned int caps;
                unsigned int type;
-               unsigned int config;
 
                caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
                type = get_wcaps_type(caps);
@@ -981,32 +1040,14 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
                switch (type) {
                case AC_WID_AUD_OUT:
-                       if (num_tmp_cvts >= MAX_HDMI_CVTS) {
-                               snd_printk(KERN_WARNING
-                                          "HDMI: no space for converter %d\n", nid);
-                               continue;
-                       }
-                       tmp_cvt[num_tmp_cvts] = nid;
-                       num_tmp_cvts++;
+                       hdmi_add_cvt(codec, nid);
                        break;
                case AC_WID_PIN:
-                       caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
-                       if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
-                               continue;
-
-                       config = snd_hda_codec_read(codec, nid, 0,
-                                            AC_VERB_GET_CONFIG_DEFAULT, 0);
-                       if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
-                               continue;
-
                        hdmi_add_pin(codec, nid);
                        break;
                }
        }
 
-       for (i = 0; i < num_tmp_cvts; i++)
-               hdmi_add_cvt(codec, tmp_cvt[i]);
-
        /*
         * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
         * can be lost and presence sense verb will become inaccurate if the
@@ -1023,7 +1064,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
 /*
  */
-static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
+static char *generic_hdmi_pcm_names[MAX_HDMI_PINS] = {
        "HDMI 0",
        "HDMI 1",
        "HDMI 2",
@@ -1040,51 +1081,84 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                           unsigned int format,
                                           struct snd_pcm_substream *substream)
 {
-       hdmi_set_channel_count(codec, hinfo->nid,
-                              substream->runtime->channels);
+       hda_nid_t cvt_nid = hinfo->nid;
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx = hinfo_to_pin_index(spec, hinfo);
+       hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
+
+       hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
 
-       hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
+       hdmi_setup_audio_infoframe(codec, pin_idx, substream);
 
-       return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
+       return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
 }
 
-static const struct hda_pcm_stream generic_hdmi_pcm_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .ops = {
-               .open = hdmi_pcm_open,
-               .prepare = generic_hdmi_playback_pcm_prepare,
-       },
+static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                            struct hda_codec *codec,
+                                            struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int cvt_idx, pin_idx;
+       struct hdmi_spec_per_cvt *per_cvt;
+       struct hdmi_spec_per_pin *per_pin;
+       int pinctl;
+
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+
+       if (hinfo->nid) {
+               cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
+               if (snd_BUG_ON(cvt_idx < 0))
+                       return -EINVAL;
+               per_cvt = &spec->cvts[cvt_idx];
+
+               snd_BUG_ON(!per_cvt->assigned);
+               per_cvt->assigned = 0;
+               hinfo->nid = 0;
+
+               pin_idx = hinfo_to_pin_index(spec, hinfo);
+               if (snd_BUG_ON(pin_idx < 0))
+                       return -EINVAL;
+               per_pin = &spec->pins[pin_idx];
+
+               pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   pinctl & ~PIN_OUT);
+               snd_hda_spdif_ctls_unassign(codec, pin_idx);
+       }
+
+       return 0;
+}
+
+static const struct hda_pcm_ops generic_ops = {
+       .open = hdmi_pcm_open,
+       .prepare = generic_hdmi_playback_pcm_prepare,
+       .cleanup = generic_hdmi_playback_pcm_cleanup,
 };
 
 static int generic_hdmi_build_pcms(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-       int i;
+       int pin_idx;
 
-       codec->num_pcms = spec->num_cvts;
-       codec->pcm_info = info;
-
-       for (i = 0; i < codec->num_pcms; i++, info++) {
-               unsigned int chans;
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hda_pcm *info;
                struct hda_pcm_stream *pstr;
 
-               chans = get_wcaps(codec, spec->cvt[i]);
-               chans = get_wcaps_channels(chans);
-
-               info->name = generic_hdmi_pcm_names[i];
+               info = &spec->pcm_rec[pin_idx];
+               info->name = generic_hdmi_pcm_names[pin_idx];
                info->pcm_type = HDA_PCM_TYPE_HDMI;
+
                pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
-               if (spec->pcm_playback)
-                       *pstr = *spec->pcm_playback;
-               else
-                       *pstr = generic_hdmi_pcm_playback;
-               pstr->nid = spec->cvt[i];
-               if (pstr->channels_max <= 2 && chans && chans <= 16)
-                       pstr->channels_max = chans;
+               pstr->substreams = 1;
+               pstr->ops = generic_ops;
+               /* other pstr fields are set in open */
        }
 
+       codec->num_pcms = spec->num_pins;
+       codec->pcm_info = spec->pcm_rec;
+
        return 0;
 }
 
@@ -1092,12 +1166,16 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
        int err;
-       int i;
+       int pin_idx;
 
-       for (i = 0; i < codec->num_pcms; i++) {
-               err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+               err = snd_hda_create_spdif_out_ctls(codec,
+                                                   per_pin->pin_nid,
+                                                   per_pin->mux_nids[0]);
                if (err < 0)
                        return err;
+               snd_hda_spdif_ctls_unassign(codec, pin_idx);
        }
 
        return 0;
@@ -1106,13 +1184,19 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 static int generic_hdmi_init(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
-       int i;
+       int pin_idx;
 
-       for (i = 0; spec->pin[i]; i++) {
-               hdmi_enable_output(codec, spec->pin[i]);
-               snd_hda_codec_write(codec, spec->pin[i], 0,
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+               hda_nid_t pin_nid = per_pin->pin_nid;
+               struct hdmi_eld *eld = &per_pin->sink_eld;
+
+               hdmi_init_pin(codec, pin_nid);
+               snd_hda_codec_write(codec, pin_nid, 0,
                                    AC_VERB_SET_UNSOLICITED_ENABLE,
-                                   AC_USRSP_EN | spec->pin[i]);
+                                   AC_USRSP_EN | pin_nid);
+
+               snd_hda_eld_proc_new(codec, eld, pin_idx);
        }
        return 0;
 }
@@ -1120,10 +1204,14 @@ static int generic_hdmi_init(struct hda_codec *codec)
 static void generic_hdmi_free(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
-       int i;
+       int pin_idx;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+               struct hdmi_eld *eld = &per_pin->sink_eld;
 
-       for (i = 0; i < spec->num_pins; i++)
-               snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
+               snd_hda_eld_proc_free(codec, eld);
+       }
        snd_hda_input_jack_free(codec);
 
        kfree(spec);
@@ -1140,7 +1228,6 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
 static int patch_generic_hdmi(struct hda_codec *codec)
 {
        struct hdmi_spec *spec;
-       int i;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -1154,14 +1241,68 @@ static int patch_generic_hdmi(struct hda_codec *codec)
        }
        codec->patch_ops = generic_hdmi_patch_ops;
 
-       for (i = 0; i < spec->num_pins; i++)
-               snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
-
        init_channel_allocations();
 
        return 0;
 }
 
+/*
+ * Shared non-generic implementations
+ */
+
+static int simple_playback_build_pcms(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_pcm *info = spec->pcm_rec;
+       int i;
+
+       codec->num_pcms = spec->num_cvts;
+       codec->pcm_info = info;
+
+       for (i = 0; i < codec->num_pcms; i++, info++) {
+               unsigned int chans;
+               struct hda_pcm_stream *pstr;
+
+               chans = get_wcaps(codec, spec->cvts[i].cvt_nid);
+               chans = get_wcaps_channels(chans);
+
+               info->name = generic_hdmi_pcm_names[i];
+               info->pcm_type = HDA_PCM_TYPE_HDMI;
+               pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+               snd_BUG_ON(!spec->pcm_playback);
+               *pstr = *spec->pcm_playback;
+               pstr->nid = spec->cvts[i].cvt_nid;
+               if (pstr->channels_max <= 2 && chans && chans <= 16)
+                       pstr->channels_max = chans;
+       }
+
+       return 0;
+}
+
+static int simple_playback_build_controls(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int err;
+       int i;
+
+       for (i = 0; i < codec->num_pcms; i++) {
+               err = snd_hda_create_spdif_out_ctls(codec,
+                                                   spec->cvts[i].cvt_nid,
+                                                   spec->cvts[i].cvt_nid);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static void simple_playback_free(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       kfree(spec);
+}
+
 /*
  * Nvidia specific implementations
  */
@@ -1352,6 +1493,9 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
        int chs;
        unsigned int dataDCC1, dataDCC2, channel_id;
        int i;
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_spdif_out *spdif =
+               snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
 
        mutex_lock(&codec->spdif_mutex);
 
@@ -1361,12 +1505,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
        dataDCC2 = 0x2;
 
        /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
                snd_hda_codec_write(codec,
                                nvhdmi_master_con_nid_7x,
                                0,
                                AC_VERB_SET_DIGI_CONVERT_1,
-                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+                               spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
 
        /* set the stream id */
        snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
@@ -1378,12 +1522,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
 
        /* turn on again (if needed) */
        /* enable and set the channel status audio/data flag */
-       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
                snd_hda_codec_write(codec,
                                nvhdmi_master_con_nid_7x,
                                0,
                                AC_VERB_SET_DIGI_CONVERT_1,
-                               codec->spdif_ctls & 0xff);
+                               spdif->ctls & 0xff);
                snd_hda_codec_write(codec,
                                nvhdmi_master_con_nid_7x,
                                0,
@@ -1400,12 +1544,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
                 *otherwise the IEC958 bits won't be updated
                 */
                if (codec->spdif_status_reset &&
-               (codec->spdif_ctls & AC_DIG1_ENABLE))
+               (spdif->ctls & AC_DIG1_ENABLE))
                        snd_hda_codec_write(codec,
                                nvhdmi_con_nids_7x[i],
                                0,
                                AC_VERB_SET_DIGI_CONVERT_1,
-                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+                               spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
                /* set the stream id */
                snd_hda_codec_write(codec,
                                nvhdmi_con_nids_7x[i],
@@ -1421,12 +1565,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
                /* turn on again (if needed) */
                /* enable and set the channel status audio/data flag */
                if (codec->spdif_status_reset &&
-               (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+               (spdif->ctls & AC_DIG1_ENABLE)) {
                        snd_hda_codec_write(codec,
                                        nvhdmi_con_nids_7x[i],
                                        0,
                                        AC_VERB_SET_DIGI_CONVERT_1,
-                                       codec->spdif_ctls & 0xff);
+                                       spdif->ctls & 0xff);
                        snd_hda_codec_write(codec,
                                        nvhdmi_con_nids_7x[i],
                                        0,
@@ -1471,17 +1615,17 @@ static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
 };
 
 static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
-       .build_controls = generic_hdmi_build_controls,
-       .build_pcms = generic_hdmi_build_pcms,
+       .build_controls = simple_playback_build_controls,
+       .build_pcms = simple_playback_build_pcms,
        .init = nvhdmi_7x_init,
-       .free = generic_hdmi_free,
+       .free = simple_playback_free,
 };
 
 static const struct hda_codec_ops nvhdmi_patch_ops_2ch = {
-       .build_controls = generic_hdmi_build_controls,
-       .build_pcms = generic_hdmi_build_pcms,
+       .build_controls = simple_playback_build_controls,
+       .build_pcms = simple_playback_build_pcms,
        .init = nvhdmi_7x_init,
-       .free = generic_hdmi_free,
+       .free = simple_playback_free,
 };
 
 static int patch_nvhdmi_2ch(struct hda_codec *codec)
@@ -1498,7 +1642,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
        spec->multiout.max_channels = 2;
        spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
        spec->num_cvts = 1;
-       spec->cvt[0] = nvhdmi_master_con_nid_7x;
+       spec->cvts[0].cvt_nid = nvhdmi_master_con_nid_7x;
        spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
 
        codec->patch_ops = nvhdmi_patch_ops_2ch;
@@ -1549,11 +1693,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                          substream);
        if (err < 0)
                return err;
-       snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT,
-                           chans - 1);
+       snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
+                           AC_VERB_SET_CVT_CHAN_COUNT, chans - 1);
        /* FIXME: XXX */
        for (i = 0; i < chans; i++) {
-               snd_hda_codec_write(codec, spec->cvt[0], 0,
+               snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
                                    AC_VERB_SET_HDMI_CHAN_SLOT,
                                    (i << 4) | i);
        }
@@ -1584,18 +1728,18 @@ static int atihdmi_init(struct hda_codec *codec)
 
        snd_hda_sequence_write(codec, atihdmi_basic_init);
        /* SI codec requires to unmute the pin */
-       if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP)
-               snd_hda_codec_write(codec, spec->pin[0], 0,
+       if (get_wcaps(codec, spec->pins[0].pin_nid) & AC_WCAP_OUT_AMP)
+               snd_hda_codec_write(codec, spec->pins[0].pin_nid, 0,
                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_OUT_UNMUTE);
        return 0;
 }
 
 static const struct hda_codec_ops atihdmi_patch_ops = {
-       .build_controls = generic_hdmi_build_controls,
-       .build_pcms = generic_hdmi_build_pcms,
+       .build_controls = simple_playback_build_controls,
+       .build_pcms = simple_playback_build_pcms,
        .init = atihdmi_init,
-       .free = generic_hdmi_free,
+       .free = simple_playback_free,
 };
 
 
@@ -1613,8 +1757,8 @@ static int patch_atihdmi(struct hda_codec *codec)
        spec->multiout.max_channels = 2;
        spec->multiout.dig_out_nid = ATIHDMI_CVT_NID;
        spec->num_cvts = 1;
-       spec->cvt[0] = ATIHDMI_CVT_NID;
-       spec->pin[0] = ATIHDMI_PIN_NID;
+       spec->cvts[0].cvt_nid = ATIHDMI_CVT_NID;
+       spec->pins[0].pin_nid = ATIHDMI_PIN_NID;
        spec->pcm_playback = &atihdmi_pcm_digital_playback;
 
        codec->patch_ops = atihdmi_patch_ops;
index b48fb43..52ce075 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Universal Interface for Intel High Definition Audio Codec
  *
- * HD audio interface patch for ALC 260/880/882 codecs
+ * HD audio interface patch for Realtek ALC codecs
  *
  * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
  *                    PeiSen Hou <pshou@realtek.com.tw>
 #include "hda_local.h"
 #include "hda_beep.h"
 
-#define ALC880_FRONT_EVENT             0x01
-#define ALC880_DCVOL_EVENT             0x02
-#define ALC880_HP_EVENT                        0x04
-#define ALC880_MIC_EVENT               0x08
-
-/* ALC880 board config type */
-enum {
-       ALC880_3ST,
-       ALC880_3ST_DIG,
-       ALC880_5ST,
-       ALC880_5ST_DIG,
-       ALC880_W810,
-       ALC880_Z71V,
-       ALC880_6ST,
-       ALC880_6ST_DIG,
-       ALC880_F1734,
-       ALC880_ASUS,
-       ALC880_ASUS_DIG,
-       ALC880_ASUS_W1V,
-       ALC880_ASUS_DIG2,
-       ALC880_FUJITSU,
-       ALC880_UNIWILL_DIG,
-       ALC880_UNIWILL,
-       ALC880_UNIWILL_P53,
-       ALC880_CLEVO,
-       ALC880_TCL_S700,
-       ALC880_LG,
-       ALC880_LG_LW,
-       ALC880_MEDION_RIM,
-#ifdef CONFIG_SND_DEBUG
-       ALC880_TEST,
-#endif
-       ALC880_AUTO,
-       ALC880_MODEL_LAST /* last tag */
-};
-
-/* ALC260 models */
-enum {
-       ALC260_BASIC,
-       ALC260_HP,
-       ALC260_HP_DC7600,
-       ALC260_HP_3013,
-       ALC260_FUJITSU_S702X,
-       ALC260_ACER,
-       ALC260_WILL,
-       ALC260_REPLACER_672V,
-       ALC260_FAVORIT100,
-#ifdef CONFIG_SND_DEBUG
-       ALC260_TEST,
-#endif
-       ALC260_AUTO,
-       ALC260_MODEL_LAST /* last tag */
-};
-
-/* ALC262 models */
-enum {
-       ALC262_BASIC,
-       ALC262_HIPPO,
-       ALC262_HIPPO_1,
-       ALC262_FUJITSU,
-       ALC262_HP_BPC,
-       ALC262_HP_BPC_D7000_WL,
-       ALC262_HP_BPC_D7000_WF,
-       ALC262_HP_TC_T5735,
-       ALC262_HP_RP5700,
-       ALC262_BENQ_ED8,
-       ALC262_SONY_ASSAMD,
-       ALC262_BENQ_T31,
-       ALC262_ULTRA,
-       ALC262_LENOVO_3000,
-       ALC262_NEC,
-       ALC262_TOSHIBA_S06,
-       ALC262_TOSHIBA_RX1,
-       ALC262_TYAN,
-       ALC262_AUTO,
-       ALC262_MODEL_LAST /* last tag */
-};
-
-/* ALC268 models */
-enum {
-       ALC267_QUANTA_IL1,
-       ALC268_3ST,
-       ALC268_TOSHIBA,
-       ALC268_ACER,
-       ALC268_ACER_DMIC,
-       ALC268_ACER_ASPIRE_ONE,
-       ALC268_DELL,
-       ALC268_ZEPTO,
-#ifdef CONFIG_SND_DEBUG
-       ALC268_TEST,
-#endif
-       ALC268_AUTO,
-       ALC268_MODEL_LAST /* last tag */
-};
-
-/* ALC269 models */
-enum {
-       ALC269_BASIC,
-       ALC269_QUANTA_FL1,
-       ALC269_AMIC,
-       ALC269_DMIC,
-       ALC269VB_AMIC,
-       ALC269VB_DMIC,
-       ALC269_FUJITSU,
-       ALC269_LIFEBOOK,
-       ALC271_ACER,
-       ALC269_AUTO,
-       ALC269_MODEL_LAST /* last tag */
-};
-
-/* ALC861 models */
-enum {
-       ALC861_3ST,
-       ALC660_3ST,
-       ALC861_3ST_DIG,
-       ALC861_6ST_DIG,
-       ALC861_UNIWILL_M31,
-       ALC861_TOSHIBA,
-       ALC861_ASUS,
-       ALC861_ASUS_LAPTOP,
-       ALC861_AUTO,
-       ALC861_MODEL_LAST,
-};
-
-/* ALC861-VD models */
-enum {
-       ALC660VD_3ST,
-       ALC660VD_3ST_DIG,
-       ALC660VD_ASUS_V1S,
-       ALC861VD_3ST,
-       ALC861VD_3ST_DIG,
-       ALC861VD_6ST_DIG,
-       ALC861VD_LENOVO,
-       ALC861VD_DALLAS,
-       ALC861VD_HP,
-       ALC861VD_AUTO,
-       ALC861VD_MODEL_LAST,
-};
-
-/* ALC662 models */
-enum {
-       ALC662_3ST_2ch_DIG,
-       ALC662_3ST_6ch_DIG,
-       ALC662_3ST_6ch,
-       ALC662_5ST_DIG,
-       ALC662_LENOVO_101E,
-       ALC662_ASUS_EEEPC_P701,
-       ALC662_ASUS_EEEPC_EP20,
-       ALC663_ASUS_M51VA,
-       ALC663_ASUS_G71V,
-       ALC663_ASUS_H13,
-       ALC663_ASUS_G50V,
-       ALC662_ECS,
-       ALC663_ASUS_MODE1,
-       ALC662_ASUS_MODE2,
-       ALC663_ASUS_MODE3,
-       ALC663_ASUS_MODE4,
-       ALC663_ASUS_MODE5,
-       ALC663_ASUS_MODE6,
-       ALC663_ASUS_MODE7,
-       ALC663_ASUS_MODE8,
-       ALC272_DELL,
-       ALC272_DELL_ZM1,
-       ALC272_SAMSUNG_NC10,
-       ALC662_AUTO,
-       ALC662_MODEL_LAST,
-};
-
-/* ALC882 models */
-enum {
-       ALC882_3ST_DIG,
-       ALC882_6ST_DIG,
-       ALC882_ARIMA,
-       ALC882_W2JC,
-       ALC882_TARGA,
-       ALC882_ASUS_A7J,
-       ALC882_ASUS_A7M,
-       ALC885_MACPRO,
-       ALC885_MBA21,
-       ALC885_MBP3,
-       ALC885_MB5,
-       ALC885_MACMINI3,
-       ALC885_IMAC24,
-       ALC885_IMAC91,
-       ALC883_3ST_2ch_DIG,
-       ALC883_3ST_6ch_DIG,
-       ALC883_3ST_6ch,
-       ALC883_6ST_DIG,
-       ALC883_TARGA_DIG,
-       ALC883_TARGA_2ch_DIG,
-       ALC883_TARGA_8ch_DIG,
-       ALC883_ACER,
-       ALC883_ACER_ASPIRE,
-       ALC888_ACER_ASPIRE_4930G,
-       ALC888_ACER_ASPIRE_6530G,
-       ALC888_ACER_ASPIRE_8930G,
-       ALC888_ACER_ASPIRE_7730G,
-       ALC883_MEDION,
-       ALC883_MEDION_WIM2160,
-       ALC883_LAPTOP_EAPD,
-       ALC883_LENOVO_101E_2ch,
-       ALC883_LENOVO_NB0763,
-       ALC888_LENOVO_MS7195_DIG,
-       ALC888_LENOVO_SKY,
-       ALC883_HAIER_W66,
-       ALC888_3ST_HP,
-       ALC888_6ST_DELL,
-       ALC883_MITAC,
-       ALC883_CLEVO_M540R,
-       ALC883_CLEVO_M720,
-       ALC883_FUJITSU_PI2515,
-       ALC888_FUJITSU_XA3530,
-       ALC883_3ST_6ch_INTEL,
-       ALC889A_INTEL,
-       ALC889_INTEL,
-       ALC888_ASUS_M90V,
-       ALC888_ASUS_EEE1601,
-       ALC889A_MB31,
-       ALC1200_ASUS_P5Q,
-       ALC883_SONY_VAIO_TT,
-       ALC882_AUTO,
-       ALC882_MODEL_LAST,
-};
-
-/* ALC680 models */
-enum {
-       ALC680_BASE,
-       ALC680_AUTO,
-       ALC680_MODEL_LAST,
-};
+/* unsol event tags */
+#define ALC_FRONT_EVENT                0x01
+#define ALC_DCVOL_EVENT                0x02
+#define ALC_HP_EVENT           0x04
+#define ALC_MIC_EVENT          0x08
 
 /* for GPIO Poll */
 #define GPIO_MASK      0x03
@@ -276,14 +51,6 @@ enum {
        ALC_INIT_GPIO3,
 };
 
-struct alc_mic_route {
-       hda_nid_t pin;
-       unsigned char mux_idx;
-       unsigned char amix_idx;
-};
-
-#define MUX_IDX_UNDEF  ((unsigned char)-1)
-
 struct alc_customize_define {
        unsigned int  sku_cfg;
        unsigned char port_connectivity;
@@ -348,9 +115,9 @@ struct alc_spec {
        const hda_nid_t *adc_nids;
        const hda_nid_t *capsrc_nids;
        hda_nid_t dig_in_nid;           /* digital-in NID; optional */
+       hda_nid_t mixer_nid;            /* analog-mixer NID */
 
        /* capture setup for dynamic dual-adc switch */
-       unsigned int cur_adc_idx;
        hda_nid_t cur_adc;
        unsigned int cur_adc_stream_tag;
        unsigned int cur_adc_format;
@@ -359,9 +126,9 @@ struct alc_spec {
        unsigned int num_mux_defs;
        const struct hda_input_mux *input_mux;
        unsigned int cur_mux[3];
-       struct alc_mic_route ext_mic;
-       struct alc_mic_route dock_mic;
-       struct alc_mic_route int_mic;
+       hda_nid_t ext_mic_pin;
+       hda_nid_t dock_mic_pin;
+       hda_nid_t int_mic_pin;
 
        /* channel model */
        const struct hda_channel_mode *channel_mode;
@@ -381,6 +148,9 @@ struct alc_spec {
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
        hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
        hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
+       hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
+       unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
+       int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */
 
        /* hooks */
        void (*init_hook)(struct hda_codec *codec);
@@ -395,6 +165,7 @@ struct alc_spec {
        unsigned int line_jack_present:1;
        unsigned int master_mute:1;
        unsigned int auto_mic:1;
+       unsigned int auto_mic_valid_imux:1;     /* valid imux for auto-mic */
        unsigned int automute:1;        /* HP automute enabled */
        unsigned int detect_line:1;     /* Line-out detection enabled */
        unsigned int automute_lines:1;  /* automute line-out as well */
@@ -402,8 +173,9 @@ struct alc_spec {
 
        /* other flags */
        unsigned int no_analog :1; /* digital I/O only */
-       unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
+       unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
        unsigned int single_input_src:1;
+       unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
 
        /* auto-mute control */
        int automute_mode;
@@ -432,39 +204,23 @@ struct alc_spec {
        struct alc_multi_io multi_io[4];
 };
 
-/*
- * configuration template - to be copied to the spec instance
- */
-struct alc_config_preset {
-       const struct snd_kcontrol_new *mixers[5]; /* should be identical size
-                                            * with spec
-                                            */
-       const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
-       const struct hda_verb *init_verbs[5];
-       unsigned int num_dacs;
-       const hda_nid_t *dac_nids;
-       hda_nid_t dig_out_nid;          /* optional */
-       hda_nid_t hp_nid;               /* optional */
-       const hda_nid_t *slave_dig_outs;
-       unsigned int num_adc_nids;
-       const hda_nid_t *adc_nids;
-       const hda_nid_t *capsrc_nids;
-       hda_nid_t dig_in_nid;
-       unsigned int num_channel_mode;
-       const struct hda_channel_mode *channel_mode;
-       int need_dac_fix;
-       int const_channel_count;
-       unsigned int num_mux_defs;
-       const struct hda_input_mux *input_mux;
-       void (*unsol_event)(struct hda_codec *, unsigned int);
-       void (*setup)(struct hda_codec *);
-       void (*init_hook)(struct hda_codec *);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       const struct hda_amp_list *loopbacks;
-       void (*power_hook)(struct hda_codec *codec);
-#endif
-};
+#define ALC_MODEL_AUTO         0       /* common for all chips */
+
+static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
+                          int dir, unsigned int bits)
+{
+       if (!nid)
+               return false;
+       if (get_wcaps(codec, nid) & (1 << (dir + 1)))
+               if (query_amp_caps(codec, nid, dir) & bits)
+                       return true;
+       return false;
+}
 
+#define nid_has_mute(codec, nid, dir) \
+       check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
+#define nid_has_volume(codec, nid, dir) \
+       check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
 
 /*
  * input MUX handling
@@ -493,388 +249,83 @@ static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
+static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
+
+       if (spec->cur_adc && spec->cur_adc != new_adc) {
+               /* stream is running, let's swap the current ADC */
+               __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+               spec->cur_adc = new_adc;
+               snd_hda_codec_setup_stream(codec, new_adc,
+                                          spec->cur_adc_stream_tag, 0,
+                                          spec->cur_adc_format);
+               return true;
+       }
+       return false;
+}
+
+/* select the given imux item; either unmute exclusively or select the route */
+static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
+                         unsigned int idx, bool force)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
        const struct hda_input_mux *imux;
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned int mux_idx;
-       hda_nid_t nid = spec->capsrc_nids ?
-               spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
-       unsigned int type;
+       int i, type;
+       hda_nid_t nid;
 
        mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
        imux = &spec->input_mux[mux_idx];
        if (!imux->num_items && mux_idx > 0)
                imux = &spec->input_mux[0];
 
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+       if (spec->cur_mux[adc_idx] == idx && !force)
+               return 0;
+       spec->cur_mux[adc_idx] = idx;
+
+       if (spec->dyn_adc_switch) {
+               alc_dyn_adc_pcm_resetup(codec, idx);
+               adc_idx = spec->dyn_adc_idx[idx];
+       }
+
+       nid = spec->capsrc_nids ?
+               spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
+
+       /* no selection? */
+       if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
+               return 1;
+
        type = get_wcaps_type(get_wcaps(codec, nid));
        if (type == AC_WID_AUD_MIX) {
                /* Matrix-mixer style (e.g. ALC882) */
-               unsigned int *cur_val = &spec->cur_mux[adc_idx];
-               unsigned int i, idx;
-
-               idx = ucontrol->value.enumerated.item[0];
-               if (idx >= imux->num_items)
-                       idx = imux->num_items - 1;
-               if (*cur_val == idx)
-                       return 0;
                for (i = 0; i < imux->num_items; i++) {
                        unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
                        snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
                                                 imux->items[i].index,
                                                 HDA_AMP_MUTE, v);
                }
-               *cur_val = idx;
-               return 1;
        } else {
                /* MUX style (e.g. ALC880) */
-               return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
-                                            &spec->cur_mux[adc_idx]);
-       }
-}
-
-/*
- * channel mode setting
- */
-static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
-                                   spec->num_channel_mode);
-}
-
-static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
-                                  spec->num_channel_mode,
-                                  spec->ext_channel_count);
-}
-
-static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
-                                     spec->num_channel_mode,
-                                     &spec->ext_channel_count);
-       if (err >= 0 && !spec->const_channel_count) {
-               spec->multiout.max_channels = spec->ext_channel_count;
-               if (spec->need_dac_fix)
-                       spec->multiout.num_dacs = spec->multiout.max_channels / 2;
-       }
-       return err;
-}
-
-/*
- * Control the mode of pin widget settings via the mixer.  "pc" is used
- * instead of "%" to avoid consequences of accidentally treating the % as
- * being part of a format specifier.  Maximum allowed length of a value is
- * 63 characters plus NULL terminator.
- *
- * Note: some retasking pin complexes seem to ignore requests for input
- * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
- * are requested.  Therefore order this list so that this behaviour will not
- * cause problems when mixer clients move through the enum sequentially.
- * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
- * March 2006.
- */
-static const char * const alc_pin_mode_names[] = {
-       "Mic 50pc bias", "Mic 80pc bias",
-       "Line in", "Line out", "Headphone out",
-};
-static const unsigned char alc_pin_mode_values[] = {
-       PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
-};
-/* The control can present all 5 options, or it can limit the options based
- * in the pin being assumed to be exclusively an input or an output pin.  In
- * addition, "input" pins may or may not process the mic bias option
- * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
- * accept requests for bias as of chip versions up to March 2006) and/or
- * wiring in the computer.
- */
-#define ALC_PIN_DIR_IN              0x00
-#define ALC_PIN_DIR_OUT             0x01
-#define ALC_PIN_DIR_INOUT           0x02
-#define ALC_PIN_DIR_IN_NOMICBIAS    0x03
-#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
-
-/* Info about the pin modes supported by the different pin direction modes.
- * For each direction the minimum and maximum values are given.
- */
-static const signed char alc_pin_mode_dir_info[5][2] = {
-       { 0, 2 },    /* ALC_PIN_DIR_IN */
-       { 3, 4 },    /* ALC_PIN_DIR_OUT */
-       { 0, 4 },    /* ALC_PIN_DIR_INOUT */
-       { 2, 2 },    /* ALC_PIN_DIR_IN_NOMICBIAS */
-       { 2, 4 },    /* ALC_PIN_DIR_INOUT_NOMICBIAS */
-};
-#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
-#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
-#define alc_pin_mode_n_items(_dir) \
-       (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
-
-static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_info *uinfo)
-{
-       unsigned int item_num = uinfo->value.enumerated.item;
-       unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
-
-       if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
-               item_num = alc_pin_mode_min(dir);
-       strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
-       return 0;
-}
-
-static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       unsigned int i;
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value & 0xffff;
-       unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
-       long *valp = ucontrol->value.integer.value;
-       unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
-                                                AC_VERB_GET_PIN_WIDGET_CONTROL,
-                                                0x00);
-
-       /* Find enumerated value for current pinctl setting */
-       i = alc_pin_mode_min(dir);
-       while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
-               i++;
-       *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
-       return 0;
-}
-
-static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       signed int change;
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value & 0xffff;
-       unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
-       long val = *ucontrol->value.integer.value;
-       unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
-                                                AC_VERB_GET_PIN_WIDGET_CONTROL,
-                                                0x00);
-
-       if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
-               val = alc_pin_mode_min(dir);
-
-       change = pinctl != alc_pin_mode_values[val];
-       if (change) {
-               /* Set pin mode to that requested */
                snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                         alc_pin_mode_values[val]);
-
-               /* Also enable the retasking pin's input/output as required
-                * for the requested pin mode.  Enum values of 2 or less are
-                * input modes.
-                *
-                * Dynamically switching the input/output buffers probably
-                * reduces noise slightly (particularly on input) so we'll
-                * do it.  However, having both input and output buffers
-                * enabled simultaneously doesn't seem to be problematic if
-                * this turns out to be necessary in the future.
-                */
-               if (val <= 2) {
-                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE, HDA_AMP_MUTE);
-                       snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
-                                                HDA_AMP_MUTE, 0);
-               } else {
-                       snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
-                                                HDA_AMP_MUTE, HDA_AMP_MUTE);
-                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE, 0);
-               }
+                                         AC_VERB_SET_CONNECT_SEL,
+                                         imux->items[idx].index);
        }
-       return change;
-}
-
-#define ALC_PIN_MODE(xname, nid, dir) \
-       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
-         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-         .info = alc_pin_mode_info, \
-         .get = alc_pin_mode_get, \
-         .put = alc_pin_mode_put, \
-         .private_value = nid | (dir<<16) }
-
-/* A switch control for ALC260 GPIO pins.  Multiple GPIOs can be ganged
- * together using a mask with more than one bit set.  This control is
- * currently used only by the ALC260 test model.  At this stage they are not
- * needed for any "production" models.
- */
-#ifdef CONFIG_SND_DEBUG
-#define alc_gpio_data_info     snd_ctl_boolean_mono_info
-
-static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value & 0xffff;
-       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-       long *valp = ucontrol->value.integer.value;
-       unsigned int val = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_GPIO_DATA, 0x00);
-
-       *valp = (val & mask) != 0;
-       return 0;
-}
-static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       signed int change;
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value & 0xffff;
-       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-       long val = *ucontrol->value.integer.value;
-       unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
-                                                   AC_VERB_GET_GPIO_DATA,
-                                                   0x00);
-
-       /* Set/unset the masked GPIO bit(s) as needed */
-       change = (val == 0 ? 0 : mask) != (gpio_data & mask);
-       if (val == 0)
-               gpio_data &= ~mask;
-       else
-               gpio_data |= mask;
-       snd_hda_codec_write_cache(codec, nid, 0,
-                                 AC_VERB_SET_GPIO_DATA, gpio_data);
-
-       return change;
-}
-#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
-       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
-         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-         .info = alc_gpio_data_info, \
-         .get = alc_gpio_data_get, \
-         .put = alc_gpio_data_put, \
-         .private_value = nid | (mask<<16) }
-#endif   /* CONFIG_SND_DEBUG */
-
-/* A switch control to allow the enabling of the digital IO pins on the
- * ALC260.  This is incredibly simplistic; the intention of this control is
- * to provide something in the test model allowing digital outputs to be
- * identified if present.  If models are found which can utilise these
- * outputs a more complete mixer control can be devised for those models if
- * necessary.
- */
-#ifdef CONFIG_SND_DEBUG
-#define alc_spdif_ctrl_info    snd_ctl_boolean_mono_info
-
-static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value & 0xffff;
-       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-       long *valp = ucontrol->value.integer.value;
-       unsigned int val = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_DIGI_CONVERT_1, 0x00);
-
-       *valp = (val & mask) != 0;
-       return 0;
-}
-static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       signed int change;
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value & 0xffff;
-       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-       long val = *ucontrol->value.integer.value;
-       unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
-                                                   AC_VERB_GET_DIGI_CONVERT_1,
-                                                   0x00);
-
-       /* Set/unset the masked control bit(s) as needed */
-       change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
-       if (val==0)
-               ctrl_data &= ~mask;
-       else
-               ctrl_data |= mask;
-       snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-                                 ctrl_data);
-
-       return change;
-}
-#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
-       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
-         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-         .info = alc_spdif_ctrl_info, \
-         .get = alc_spdif_ctrl_get, \
-         .put = alc_spdif_ctrl_put, \
-         .private_value = nid | (mask<<16) }
-#endif   /* CONFIG_SND_DEBUG */
-
-/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
- * Again, this is only used in the ALC26x test models to help identify when
- * the EAPD line must be asserted for features to work.
- */
-#ifdef CONFIG_SND_DEBUG
-#define alc_eapd_ctrl_info     snd_ctl_boolean_mono_info
-
-static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value & 0xffff;
-       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-       long *valp = ucontrol->value.integer.value;
-       unsigned int val = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_EAPD_BTLENABLE, 0x00);
-
-       *valp = (val & mask) != 0;
-       return 0;
+       return 1;
 }
 
-static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
+static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
 {
-       int change;
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value & 0xffff;
-       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-       long val = *ucontrol->value.integer.value;
-       unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
-                                                   AC_VERB_GET_EAPD_BTLENABLE,
-                                                   0x00);
-
-       /* Set/unset the masked control bit(s) as needed */
-       change = (!val ? 0 : mask) != (ctrl_data & mask);
-       if (!val)
-               ctrl_data &= ~mask;
-       else
-               ctrl_data |= mask;
-       snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
-                                 ctrl_data);
-
-       return change;
+       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       return alc_mux_select(codec, adc_idx,
+                             ucontrol->value.enumerated.item[0], false);
 }
 
-#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
-       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
-         .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-         .info = alc_eapd_ctrl_info, \
-         .get = alc_eapd_ctrl_get, \
-         .put = alc_eapd_ctrl_put, \
-         .private_value = nid | (mask<<16) }
-#endif   /* CONFIG_SND_DEBUG */
-
 /*
  * set up the input pin config (depending on the given auto-pin type)
  */
@@ -903,29 +354,10 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
 }
 
-static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-
-       if (!cfg->line_outs) {
-               while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
-                      cfg->line_out_pins[cfg->line_outs])
-                       cfg->line_outs++;
-       }
-       if (!cfg->speaker_outs) {
-               while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
-                      cfg->speaker_pins[cfg->speaker_outs])
-                       cfg->speaker_outs++;
-       }
-       if (!cfg->hp_outs) {
-               while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
-                      cfg->hp_pins[cfg->hp_outs])
-                       cfg->hp_outs++;
-       }
-}
-
 /*
+ * Append the given mixer and verb elements for the later use
+ * The mixer array is referred in build_controls(), and init_verbs are
+ * called in init().
  */
 static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
 {
@@ -942,61 +374,8 @@ static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
 }
 
 /*
- * set up from the preset table
+ * GPIO setup tables, used in initialization
  */
-static void setup_preset(struct hda_codec *codec,
-                        const struct alc_config_preset *preset)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
-               add_mixer(spec, preset->mixers[i]);
-       spec->cap_mixer = preset->cap_mixer;
-       for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
-            i++)
-               add_verb(spec, preset->init_verbs[i]);
-
-       spec->channel_mode = preset->channel_mode;
-       spec->num_channel_mode = preset->num_channel_mode;
-       spec->need_dac_fix = preset->need_dac_fix;
-       spec->const_channel_count = preset->const_channel_count;
-
-       if (preset->const_channel_count)
-               spec->multiout.max_channels = preset->const_channel_count;
-       else
-               spec->multiout.max_channels = spec->channel_mode[0].channels;
-       spec->ext_channel_count = spec->channel_mode[0].channels;
-
-       spec->multiout.num_dacs = preset->num_dacs;
-       spec->multiout.dac_nids = preset->dac_nids;
-       spec->multiout.dig_out_nid = preset->dig_out_nid;
-       spec->multiout.slave_dig_outs = preset->slave_dig_outs;
-       spec->multiout.hp_nid = preset->hp_nid;
-
-       spec->num_mux_defs = preset->num_mux_defs;
-       if (!spec->num_mux_defs)
-               spec->num_mux_defs = 1;
-       spec->input_mux = preset->input_mux;
-
-       spec->num_adc_nids = preset->num_adc_nids;
-       spec->adc_nids = preset->adc_nids;
-       spec->capsrc_nids = preset->capsrc_nids;
-       spec->dig_in_nid = preset->dig_in_nid;
-
-       spec->unsol_event = preset->unsol_event;
-       spec->init_hook = preset->init_hook;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->power_hook = preset->power_hook;
-       spec->loopback.amplist = preset->loopbacks;
-#endif
-
-       if (preset->setup)
-               preset->setup(codec);
-
-       alc_fixup_autocfg_pin_nums(codec);
-}
-
 /* Enable GPIO mask and set output */
 static const struct hda_verb alc_gpio1_init_verbs[] = {
        {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
@@ -1051,14 +430,19 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
        alc_fix_pll(codec);
 }
 
+/*
+ * Jack-reporting via input-jack layer
+ */
+
+/* initialization of jacks; currently checks only a few known pins */
 static int alc_init_jacks(struct hda_codec *codec)
 {
 #ifdef CONFIG_SND_HDA_INPUT_JACK
        struct alc_spec *spec = codec->spec;
        int err;
        unsigned int hp_nid = spec->autocfg.hp_pins[0];
-       unsigned int mic_nid = spec->ext_mic.pin;
-       unsigned int dock_nid = spec->dock_mic.pin;
+       unsigned int mic_nid = spec->ext_mic_pin;
+       unsigned int dock_nid = spec->dock_mic_pin;
 
        if (hp_nid) {
                err = snd_hda_input_jack_add(codec, hp_nid,
@@ -1086,7 +470,12 @@ static int alc_init_jacks(struct hda_codec *codec)
        return 0;
 }
 
-static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
+/*
+ * Jack detections for HP auto-mute and mic-switch
+ */
+
+/* check each pin in the given array; returns true if any of them is plugged */
+static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
 {
        int i, present = 0;
 
@@ -1100,6 +489,7 @@ static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
        return present;
 }
 
+/* standard HP/line-out auto-mute helper */
 static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
                        bool mute, bool hp_out)
 {
@@ -1170,6 +560,7 @@ static void update_speakers(struct hda_codec *codec)
                    spec->autocfg.line_out_pins, on, false);
 }
 
+/* standard HP-automute helper */
 static void alc_hp_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -1182,6 +573,7 @@ static void alc_hp_automute(struct hda_codec *codec)
        update_speakers(codec);
 }
 
+/* standard line-out-automute helper */
 static void alc_line_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -1194,106 +586,33 @@ static void alc_line_automute(struct hda_codec *codec)
        update_speakers(codec);
 }
 
-static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
-                               hda_nid_t nid)
-{
-       hda_nid_t conn[HDA_MAX_NUM_INPUTS];
-       int i, nums;
-
-       nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
-       for (i = 0; i < nums; i++)
-               if (conn[i] == nid)
-                       return i;
-       return -1;
-}
-
-/* switch the current ADC according to the jack state */
-static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       unsigned int present;
-       hda_nid_t new_adc;
-
-       present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
-       if (present)
-               spec->cur_adc_idx = 1;
-       else
-               spec->cur_adc_idx = 0;
-       new_adc = spec->adc_nids[spec->cur_adc_idx];
-       if (spec->cur_adc && spec->cur_adc != new_adc) {
-               /* stream is running, let's swap the current ADC */
-               __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
-               spec->cur_adc = new_adc;
-               snd_hda_codec_setup_stream(codec, new_adc,
-                                          spec->cur_adc_stream_tag, 0,
-                                          spec->cur_adc_format);
-       }
-}
+#define get_connection_index(codec, mux, nid) \
+       snd_hda_get_conn_index(codec, mux, nid, 0)
 
+/* standard mic auto-switch helper */
 static void alc_mic_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       struct alc_mic_route *dead1, *dead2, *alive;
-       unsigned int present, type;
-       hda_nid_t cap_nid;
+       hda_nid_t *pins = spec->imux_pins;
 
-       if (!spec->auto_mic)
-               return;
-       if (!spec->int_mic.pin || !spec->ext_mic.pin)
+       if (!spec->auto_mic || !spec->auto_mic_valid_imux)
                return;
        if (snd_BUG_ON(!spec->adc_nids))
                return;
-
-       if (spec->dual_adc_switch) {
-               alc_dual_mic_adc_auto_switch(codec);
+       if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0))
                return;
-       }
 
-       cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
-
-       alive = &spec->int_mic;
-       dead1 = &spec->ext_mic;
-       dead2 = &spec->dock_mic;
-
-       present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
-       if (present) {
-               alive = &spec->ext_mic;
-               dead1 = &spec->int_mic;
-               dead2 = &spec->dock_mic;
-       }
-       if (!present && spec->dock_mic.pin > 0) {
-               present = snd_hda_jack_detect(codec, spec->dock_mic.pin);
-               if (present) {
-                       alive = &spec->dock_mic;
-                       dead1 = &spec->int_mic;
-                       dead2 = &spec->ext_mic;
-               }
-               snd_hda_input_jack_report(codec, spec->dock_mic.pin);
-       }
-
-       type = get_wcaps_type(get_wcaps(codec, cap_nid));
-       if (type == AC_WID_AUD_MIX) {
-               /* Matrix-mixer style (e.g. ALC882) */
-               snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
-                                        alive->mux_idx,
-                                        HDA_AMP_MUTE, 0);
-               if (dead1->pin > 0)
-                       snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
-                                                dead1->mux_idx,
-                                                HDA_AMP_MUTE, HDA_AMP_MUTE);
-               if (dead2->pin > 0)
-                       snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
-                                                dead2->mux_idx,
-                                                HDA_AMP_MUTE, HDA_AMP_MUTE);
-       } else {
-               /* MUX style (e.g. ALC880) */
-               snd_hda_codec_write_cache(codec, cap_nid, 0,
-                                         AC_VERB_SET_CONNECT_SEL,
-                                         alive->mux_idx);
-       }
-       snd_hda_input_jack_report(codec, spec->ext_mic.pin);
+       if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx]))
+               alc_mux_select(codec, 0, spec->ext_mic_idx, false);
+       else if (spec->dock_mic_idx >= 0 &&
+                  snd_hda_jack_detect(codec, pins[spec->dock_mic_idx]))
+               alc_mux_select(codec, 0, spec->dock_mic_idx, false);
+       else
+               alc_mux_select(codec, 0, spec->int_mic_idx, false);
 
-       /* FIXME: analog mixer */
+       snd_hda_input_jack_report(codec, pins[spec->ext_mic_idx]);
+       if (spec->dock_mic_idx >= 0)
+               snd_hda_input_jack_report(codec, pins[spec->dock_mic_idx]);
 }
 
 /* unsolicited event for HP jack sensing */
@@ -1304,18 +623,19 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
        else
                res >>= 26;
        switch (res) {
-       case ALC880_HP_EVENT:
+       case ALC_HP_EVENT:
                alc_hp_automute(codec);
                break;
-       case ALC880_FRONT_EVENT:
+       case ALC_FRONT_EVENT:
                alc_line_automute(codec);
                break;
-       case ALC880_MIC_EVENT:
+       case ALC_MIC_EVENT:
                alc_mic_automute(codec);
                break;
        }
 }
 
+/* call init functions of standard auto-mute helpers */
 static void alc_inithook(struct hda_codec *codec)
 {
        alc_hp_automute(codec);
@@ -1341,6 +661,7 @@ static void alc888_coef_init(struct hda_codec *codec)
                                    AC_VERB_SET_PROC_COEF, 0x3030);
 }
 
+/* additional initialization for ALC889 variants */
 static void alc889_coef_init(struct hda_codec *codec)
 {
        unsigned int tmp;
@@ -1365,28 +686,12 @@ static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
 static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
 {
        /* We currently only handle front, HP */
-       switch (codec->vendor_id) {
-       case 0x10ec0260:
-               set_eapd(codec, 0x0f, on);
-               set_eapd(codec, 0x10, on);
-               break;
-       case 0x10ec0262:
-       case 0x10ec0267:
-       case 0x10ec0268:
-       case 0x10ec0269:
-       case 0x10ec0270:
-       case 0x10ec0272:
-       case 0x10ec0660:
-       case 0x10ec0662:
-       case 0x10ec0663:
-       case 0x10ec0665:
-       case 0x10ec0862:
-       case 0x10ec0889:
-       case 0x10ec0892:
-               set_eapd(codec, 0x14, on);
-               set_eapd(codec, 0x15, on);
-               break;
-       }
+       static hda_nid_t pins[] = {
+               0x0f, 0x10, 0x14, 0x15, 0
+       };
+       hda_nid_t *p;
+       for (p = pins; *p; p++)
+               set_eapd(codec, *p, on);
 }
 
 /* generic shutup callback;
@@ -1398,10 +703,12 @@ static void alc_eapd_shutup(struct hda_codec *codec)
        msleep(200);
 }
 
+/* generic EAPD initialization */
 static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
        unsigned int tmp;
 
+       alc_auto_setup_eapd(codec, true);
        switch (type) {
        case ALC_INIT_GPIO1:
                snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
@@ -1413,7 +720,6 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
                snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
                break;
        case ALC_INIT_DEFAULT:
-               alc_auto_setup_eapd(codec, true);
                switch (codec->vendor_id) {
                case 0x10ec0260:
                        snd_hda_codec_write(codec, 0x1a, 0,
@@ -1457,6 +763,9 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
        }
 }
 
+/*
+ * Auto-Mute mode mixer enum support
+ */
 static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
 {
@@ -1543,7 +852,11 @@ static const struct snd_kcontrol_new alc_automute_mode_enum = {
        .put = alc_automute_mode_put,
 };
 
-static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
+static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
+{
+       snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
+       return snd_array_new(&spec->kctls);
+}
 
 static int alc_add_automute_mode_enum(struct hda_codec *codec)
 {
@@ -1560,6 +873,10 @@ static int alc_add_automute_mode_enum(struct hda_codec *codec)
        return 0;
 }
 
+/*
+ * Check the availability of HP/line-out auto-mute;
+ * Set up appropriately if really supported
+ */
 static void alc_init_auto_hp(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -1598,7 +915,7 @@ static void alc_init_auto_hp(struct hda_codec *codec)
                            nid);
                snd_hda_codec_write_cache(codec, nid, 0,
                                  AC_VERB_SET_UNSOLICITED_ENABLE,
-                                 AC_USRSP_EN | ALC880_HP_EVENT);
+                                 AC_USRSP_EN | ALC_HP_EVENT);
                spec->automute = 1;
                spec->automute_mode = ALC_AUTOMUTE_PIN;
        }
@@ -1613,7 +930,7 @@ static void alc_init_auto_hp(struct hda_codec *codec)
                                    "on NID 0x%x\n", nid);
                        snd_hda_codec_write_cache(codec, nid, 0,
                                        AC_VERB_SET_UNSOLICITED_ENABLE,
-                                       AC_USRSP_EN | ALC880_FRONT_EVENT);
+                                       AC_USRSP_EN | ALC_FRONT_EVENT);
                        spec->detect_line = 1;
                }
                spec->automute_lines = spec->detect_line;
@@ -1626,6 +943,132 @@ static void alc_init_auto_hp(struct hda_codec *codec)
        }
 }
 
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+       int i;
+       for (i = 0; i < nums; i++)
+               if (list[i] == nid)
+                       return i;
+       return -1;
+}
+
+/* check whether dynamic ADC-switching is available */
+static bool alc_check_dyn_adc_switch(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->private_imux[0];
+       int i, n, idx;
+       hda_nid_t cap, pin;
+
+       if (imux != spec->input_mux) /* no dynamic imux? */
+               return false;
+
+       for (n = 0; n < spec->num_adc_nids; n++) {
+               cap = spec->private_capsrc_nids[n];
+               for (i = 0; i < imux->num_items; i++) {
+                       pin = spec->imux_pins[i];
+                       if (!pin)
+                               return false;
+                       if (get_connection_index(codec, cap, pin) < 0)
+                               break;
+               }
+               if (i >= imux->num_items)
+                       return true; /* no ADC-switch is needed */
+       }
+
+       for (i = 0; i < imux->num_items; i++) {
+               pin = spec->imux_pins[i];
+               for (n = 0; n < spec->num_adc_nids; n++) {
+                       cap = spec->private_capsrc_nids[n];
+                       idx = get_connection_index(codec, cap, pin);
+                       if (idx >= 0) {
+                               imux->items[i].index = idx;
+                               spec->dyn_adc_idx[i] = n;
+                               break;
+                       }
+               }
+       }
+
+       snd_printdd("realtek: enabling ADC switching\n");
+       spec->dyn_adc_switch = 1;
+       return true;
+}
+
+/* rebuild imux for matching with the given auto-mic pins (if not yet) */
+static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct hda_input_mux *imux;
+       static char * const texts[3] = {
+               "Mic", "Internal Mic", "Dock Mic"
+       };
+       int i;
+
+       if (!spec->auto_mic)
+               return false;
+       imux = &spec->private_imux[0];
+       if (spec->input_mux == imux)
+               return true;
+       spec->imux_pins[0] = spec->ext_mic_pin;
+       spec->imux_pins[1] = spec->int_mic_pin;
+       spec->imux_pins[2] = spec->dock_mic_pin;
+       for (i = 0; i < 3; i++) {
+               strcpy(imux->items[i].label, texts[i]);
+               if (spec->imux_pins[i])
+                       imux->num_items = i + 1;
+       }
+       spec->num_mux_defs = 1;
+       spec->input_mux = imux;
+       return true;
+}
+
+/* check whether all auto-mic pins are valid; setup indices if OK */
+static bool alc_auto_mic_check_imux(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       const struct hda_input_mux *imux;
+
+       if (!spec->auto_mic)
+               return false;
+       if (spec->auto_mic_valid_imux)
+               return true; /* already checked */
+
+       /* fill up imux indices */
+       if (!alc_check_dyn_adc_switch(codec)) {
+               spec->auto_mic = 0;
+               return false;
+       }
+
+       imux = spec->input_mux;
+       spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin,
+                                       spec->imux_pins, imux->num_items);
+       spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin,
+                                       spec->imux_pins, imux->num_items);
+       spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin,
+                                       spec->imux_pins, imux->num_items);
+       if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) {
+               spec->auto_mic = 0;
+               return false; /* no corresponding imux */
+       }
+
+       snd_hda_codec_write_cache(codec, spec->ext_mic_pin, 0,
+                                 AC_VERB_SET_UNSOLICITED_ENABLE,
+                                 AC_USRSP_EN | ALC_MIC_EVENT);
+       if (spec->dock_mic_pin)
+               snd_hda_codec_write_cache(codec, spec->dock_mic_pin, 0,
+                                 AC_VERB_SET_UNSOLICITED_ENABLE,
+                                 AC_USRSP_EN | ALC_MIC_EVENT);
+
+       spec->auto_mic_valid_imux = 1;
+       spec->auto_mic = 1;
+       return true;
+}
+
+/*
+ * Check the availability of auto-mic switch;
+ * Set up if really supported
+ */
 static void alc_init_auto_mic(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -1633,6 +1076,8 @@ static void alc_init_auto_mic(struct hda_codec *codec)
        hda_nid_t fixed, ext, dock;
        int i;
 
+       spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1;
+
        fixed = ext = dock = 0;
        for (i = 0; i < cfg->num_inputs; i++) {
                hda_nid_t nid = cfg->inputs[i].pin;
@@ -1674,21 +1119,32 @@ static void alc_init_auto_mic(struct hda_codec *codec)
                return; /* no unsol support */
        if (dock && !is_jack_detectable(codec, dock))
                return; /* no unsol support */
+
+       /* check imux indices */
+       spec->ext_mic_pin = ext;
+       spec->int_mic_pin = fixed;
+       spec->dock_mic_pin = dock;
+
+       spec->auto_mic = 1;
+       if (!alc_auto_mic_check_imux(codec))
+               return;
+
        snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
                    ext, fixed, dock);
-       spec->ext_mic.pin = ext;
-       spec->dock_mic.pin = dock;
-       spec->int_mic.pin = fixed;
-       spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
-       spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
-       spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
-       spec->auto_mic = 1;
-       snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
-                                 AC_VERB_SET_UNSOLICITED_ENABLE,
-                                 AC_USRSP_EN | ALC880_MIC_EVENT);
        spec->unsol_event = alc_sku_unsol_event;
 }
 
+/* check the availabilities of auto-mute and auto-mic switches */
+static void alc_auto_check_switches(struct hda_codec *codec)
+{
+       alc_init_auto_hp(codec);
+       alc_init_auto_mic(codec);
+}
+
+/*
+ * Realtek SSID verification
+ */
+
 /* Could be any non-zero and even value. When used as fixup, tells
  * the driver to ignore any present sku defines.
  */
@@ -1759,6 +1215,12 @@ do_sku:
        return 0;
 }
 
+/* return true if the given NID is found in the list */
+static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+       return find_idx_in_nid_list(nid, list, nums) >= 0;
+}
+
 /* check subsystem ID and set up device-specific initialization;
  * return 1 if initialized, 0 if invalid SSID
  */
@@ -1868,27 +1330,24 @@ do_sku:
                        nid = porti;
                else
                        return 1;
-               for (i = 0; i < spec->autocfg.line_outs; i++)
-                       if (spec->autocfg.line_out_pins[i] == nid)
-                               return 1;
+               if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
+                                     spec->autocfg.line_outs))
+                       return 1;
                spec->autocfg.hp_pins[0] = nid;
        }
        return 1;
 }
 
-static void alc_ssid_check(struct hda_codec *codec,
-                          hda_nid_t porta, hda_nid_t porte,
-                          hda_nid_t portd, hda_nid_t porti)
+/* Check the validity of ALC subsystem-id
+ * ports contains an array of 4 pin NIDs for port-A, E, D and I */
+static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
 {
-       if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
+       if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) {
                struct alc_spec *spec = codec->spec;
                snd_printd("realtek: "
                           "Enable default setup for auto mode as fallback\n");
                spec->init_amp = ALC_INIT_DEFAULT;
        }
-
-       alc_init_auto_hp(codec);
-       alc_init_auto_mic(codec);
 }
 
 /*
@@ -2036,6 +1495,9 @@ static void alc_pick_fixup(struct hda_codec *codec,
        }
 }
 
+/*
+ * COEF access helper functions
+ */
 static int alc_read_coef_idx(struct hda_codec *codec,
                        unsigned int coef_idx)
 {
@@ -2056,20 +1518,32 @@ static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
                            coef_val);
 }
 
+/*
+ * Digital I/O handling
+ */
+
 /* set right pin controls for digital I/O */
 static void alc_auto_init_digital(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        int i;
-       hda_nid_t pin;
+       hda_nid_t pin, dac;
 
        for (i = 0; i < spec->autocfg.dig_outs; i++) {
                pin = spec->autocfg.dig_out_pins[i];
-               if (pin) {
-                       snd_hda_codec_write(codec, pin, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           PIN_OUT);
-               }
+               if (!pin)
+                       continue;
+               snd_hda_codec_write(codec, pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               if (!i)
+                       dac = spec->multiout.dig_out_nid;
+               else
+                       dac = spec->slave_dig_outs[i - 1];
+               if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
+                       continue;
+               snd_hda_codec_write(codec, dac, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_OUT_UNMUTE);
        }
        pin = spec->autocfg.dig_in_pin;
        if (pin)
@@ -2087,11 +1561,13 @@ static void alc_auto_parse_digital(struct hda_codec *codec)
 
        /* support multiple SPDIFs; the secondary is set up as a slave */
        for (i = 0; i < spec->autocfg.dig_outs; i++) {
+               hda_nid_t conn[4];
                err = snd_hda_get_connections(codec,
                                              spec->autocfg.dig_out_pins[i],
-                                             &dig_nid, 1);
+                                             conn, ARRAY_SIZE(conn));
                if (err < 0)
                        continue;
+               dig_nid = conn[0]; /* assume the first element is audio-out */
                if (!i) {
                        spec->multiout.dig_out_nid = dig_nid;
                        spec->dig_out_type = spec->autocfg.dig_out_type[0];
@@ -2124,13960 +1600,1790 @@ static void alc_auto_parse_digital(struct hda_codec *codec)
 }
 
 /*
- * ALC888
- */
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
-/* Mic-in jack as mic in */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-/* Line-in jack as Line in */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-/* Line-Out as Front */
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
-/* Mic-in jack as mic in */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-/* Line-in jack as Surround */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-Out as Front */
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { } /* end */
-};
-
-/*
- * 6ch mode
+ * capture mixer elements
  */
-static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
-/* Mic-in jack as CLFE */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-in jack as Surround */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-       { } /* end */
-};
+static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       unsigned long val;
+       int err;
 
-/*
- * 8ch mode
- */
-static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
-/* Mic-in jack as CLFE */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-in jack as Surround */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-Out as Side */
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-       { } /* end */
-};
+       mutex_lock(&codec->control_mutex);
+       if (spec->vol_in_capsrc)
+               val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
+       else
+               val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
+       kcontrol->private_value = val;
+       err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
+       mutex_unlock(&codec->control_mutex);
+       return err;
+}
 
-static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
-       { 2, alc888_4ST_ch2_intel_init },
-       { 4, alc888_4ST_ch4_intel_init },
-       { 6, alc888_4ST_ch6_intel_init },
-       { 8, alc888_4ST_ch8_intel_init },
-};
+static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+                          unsigned int size, unsigned int __user *tlv)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       unsigned long val;
+       int err;
 
-/*
- * ALC888 Fujitsu Siemens Amillo xa3530
- */
+       mutex_lock(&codec->control_mutex);
+       if (spec->vol_in_capsrc)
+               val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
+       else
+               val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
+       kcontrol->private_value = val;
+       err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
+       mutex_unlock(&codec->control_mutex);
+       return err;
+}
 
-static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Connect Internal HP to Front */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Connect Bass HP to Front */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Connect Line-Out side jack (SPDIF) to Side */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-/* Connect Mic jack to CLFE */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
-/* Connect Line-in jack to Surround */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-/* Connect HP out jack to Front */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Enable unsolicited event for HP jack and Line-out jack */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {}
-};
+typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol);
 
-static void alc889_automute_setup(struct hda_codec *codec)
+static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol,
+                                getput_call_t func, bool check_adc_switch)
 {
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
+       int i, err = 0;
 
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x17;
-       spec->autocfg.speaker_pins[3] = 0x19;
-       spec->autocfg.speaker_pins[4] = 0x1a;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
+       mutex_lock(&codec->control_mutex);
+       if (check_adc_switch && spec->dyn_adc_switch) {
+               for (i = 0; i < spec->num_adc_nids; i++) {
+                       kcontrol->private_value =
+                               HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
+                                                   3, 0, HDA_INPUT);
+                       err = func(kcontrol, ucontrol);
+                       if (err < 0)
+                               goto error;
+               }
+       } else {
+               i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+               if (spec->vol_in_capsrc)
+                       kcontrol->private_value =
+                               HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i],
+                                                   3, 0, HDA_OUTPUT);
+               else
+                       kcontrol->private_value =
+                               HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
+                                                   3, 0, HDA_INPUT);
+               err = func(kcontrol, ucontrol);
+       }
+ error:
+       mutex_unlock(&codec->control_mutex);
+       return err;
 }
 
-static void alc889_intel_init_hook(struct hda_codec *codec)
+static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
 {
-       alc889_coef_init(codec);
-       alc_hp_automute(codec);
+       return alc_cap_getput_caller(kcontrol, ucontrol,
+                                    snd_hda_mixer_amp_volume_get, false);
 }
 
-static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
+static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
 {
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x17; /* line-out */
-       spec->autocfg.hp_pins[1] = 0x1b; /* hp */
-       spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
-       spec->autocfg.speaker_pins[1] = 0x15; /* bass */
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
+       return alc_cap_getput_caller(kcontrol, ucontrol,
+                                    snd_hda_mixer_amp_volume_put, true);
 }
 
-/*
- * ALC888 Acer Aspire 4930G model
- */
+/* capture mixer elements */
+#define alc_cap_sw_info                snd_ctl_boolean_stereo_info
 
-static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-/* Connect Internal HP to front */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Connect HP out to front */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
+static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       return alc_cap_getput_caller(kcontrol, ucontrol,
+                                    snd_hda_mixer_amp_switch_get, false);
+}
 
-/*
- * ALC888 Acer Aspire 6530G model
- */
+static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       return alc_cap_getput_caller(kcontrol, ucontrol,
+                                    snd_hda_mixer_amp_switch_put, true);
+}
 
-static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
-/* Route to built-in subwoofer as well as speakers */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-/* Bias voltage on for external mic port */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-/* Enable speaker output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-/* Enable headphone output */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
+#define _DEFINE_CAPMIX(num) \
+       { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name = "Capture Switch", \
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+               .count = num, \
+               .info = alc_cap_sw_info, \
+               .get = alc_cap_sw_get, \
+               .put = alc_cap_sw_put, \
+       }, \
+       { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name = "Capture Volume", \
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+                          SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+                          SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
+               .count = num, \
+               .info = alc_cap_vol_info, \
+               .get = alc_cap_vol_get, \
+               .put = alc_cap_vol_put, \
+               .tlv = { .c = alc_cap_vol_tlv }, \
+       }
 
-/*
- *ALC888 Acer Aspire 7730G model
- */
+#define _DEFINE_CAPSRC(num) \
+       { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               /* .name = "Capture Source", */ \
+               .name = "Input Source", \
+               .count = num, \
+               .info = alc_mux_enum_info, \
+               .get = alc_mux_enum_get, \
+               .put = alc_mux_enum_put, \
+       }
 
-static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
-/* Bias voltage on for external mic port */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-/* Enable speaker output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-/* Enable headphone output */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-/*Enable internal subwoofer */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
-       {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
+#define DEFINE_CAPMIX(num) \
+static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+       _DEFINE_CAPMIX(num),                                  \
+       _DEFINE_CAPSRC(num),                                  \
+       { } /* end */                                         \
+}
+
+#define DEFINE_CAPMIX_NOSRC(num) \
+static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
+       _DEFINE_CAPMIX(num),                                        \
+       { } /* end */                                               \
+}
+
+/* up to three ADCs */
+DEFINE_CAPMIX(1);
+DEFINE_CAPMIX(2);
+DEFINE_CAPMIX(3);
+DEFINE_CAPMIX_NOSRC(1);
+DEFINE_CAPMIX_NOSRC(2);
+DEFINE_CAPMIX_NOSRC(3);
 
 /*
- * ALC889 Acer Aspire 8930G model
+ * virtual master controls
  */
 
-static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-/* Connect Internal Front to Front */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Connect Internal Rear to Rear */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
-/* Connect Internal CLFE to CLFE */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
-/* Connect HP out to Front */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Enable all DACs */
-/*  DAC DISABLE/MUTE 1? */
-/*  setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
-/*  DAC DISABLE/MUTE 2? */
-/*  some bit here disables the other DACs. Init=0x4900 */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
-/* DMIC fix
- * This laptop has a stereo digital microphone. The mics are only 1cm apart
- * which makes the stereo useless. However, either the mic or the ALC889
- * makes the signal become a difference/sum signal instead of standard
- * stereo, which is annoying. So instead we flip this bit which makes the
- * codec replicate the sum signal to both channels, turning it into a
- * normal mono mic.
+/*
+ * slave controls for virtual master
  */
-/*  DMIC_CONTROL? Init value = 0x0001 */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
-       { }
+static const char * const alc_slave_vols[] = {
+       "Front Playback Volume",
+       "Surround Playback Volume",
+       "Center Playback Volume",
+       "LFE Playback Volume",
+       "Side Playback Volume",
+       "Headphone Playback Volume",
+       "Speaker Playback Volume",
+       "Mono Playback Volume",
+       "Line-Out Playback Volume",
+       NULL,
 };
 
-static const struct hda_input_mux alc888_2_capture_sources[2] = {
-       /* Front mic only available on one ADC */
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Front Mic", 0xb },
-               },
-       },
-       {
-               .num_items = 3,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-               },
-       }
+static const char * const alc_slave_sws[] = {
+       "Front Playback Switch",
+       "Surround Playback Switch",
+       "Center Playback Switch",
+       "LFE Playback Switch",
+       "Side Playback Switch",
+       "Headphone Playback Switch",
+       "Speaker Playback Switch",
+       "Mono Playback Switch",
+       "IEC958 Playback Switch",
+       "Line-Out Playback Switch",
+       NULL,
 };
 
-static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
-       /* Interal mic only available on one ADC */
-       {
-               .num_items = 5,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line In", 0x2 },
-                       { "CD", 0x4 },
-                       { "Input Mix", 0xa },
-                       { "Internal Mic", 0xb },
-               },
-       },
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line In", 0x2 },
-                       { "CD", 0x4 },
-                       { "Input Mix", 0xa },
-               },
-       }
-};
+/*
+ * build control elements
+ */
 
-static const struct hda_input_mux alc889_capture_sources[3] = {
-       /* Digital mic only available on first "ADC" */
-       {
-               .num_items = 5,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Front Mic", 0xb },
-                       { "Input Mix", 0xa },
-               },
-       },
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Input Mix", 0xa },
-               },
-       },
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Input Mix", 0xa },
-               },
-       }
-};
+#define NID_MAPPING            (-1)
 
-static const struct snd_kcontrol_new alc888_base_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-               HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
+#define SUBDEV_SPEAKER_                (0 << 6)
+#define SUBDEV_HP_             (1 << 6)
+#define SUBDEV_LINE_           (2 << 6)
+#define SUBDEV_SPEAKER(x)      (SUBDEV_SPEAKER_ | ((x) & 0x3f))
+#define SUBDEV_HP(x)           (SUBDEV_HP_ | ((x) & 0x3f))
+#define SUBDEV_LINE(x)         (SUBDEV_LINE_ | ((x) & 0x3f))
 
-static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-               HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
+static void alc_free_kctls(struct hda_codec *codec);
 
-static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-               HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* additional beep mixers; the actual parameters are overwritten at build */
+static const struct snd_kcontrol_new alc_beep_mixer[] = {
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
+       HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
        { } /* end */
 };
+#endif
 
-
-static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
+static int alc_build_controls(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct snd_kcontrol *kctl = NULL;
+       const struct snd_kcontrol_new *knew;
+       int i, j, err;
+       unsigned int u;
+       hda_nid_t nid;
 
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x17;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
+       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->cap_mixer) {
+               err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
+               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;
+               if (!spec->no_analog) {
+                       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;
+       }
 
-static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+       /* create beep controls if needed */
+       if (spec->beep_amp) {
+               const struct snd_kcontrol_new *knew;
+               for (knew = alc_beep_mixer; knew->name; knew++) {
+                       struct snd_kcontrol *kctl;
+                       kctl = snd_ctl_new1(knew, codec);
+                       if (!kctl)
+                               return -ENOMEM;
+                       kctl->private_value = spec->beep_amp;
+                       err = snd_hda_ctl_add(codec, 0, kctl);
+                       if (err < 0)
+                               return err;
+               }
+       }
+#endif
 
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x17;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
+       /* if we have no master control, let's create it */
+       if (!spec->no_analog &&
+           !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, alc_slave_vols);
+               if (err < 0)
+                       return err;
+       }
+       if (!spec->no_analog &&
+           !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+               err = snd_hda_add_vmaster(codec, "Master Playback Switch",
+                                         NULL, alc_slave_sws);
+               if (err < 0)
+                       return err;
+       }
 
-static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
+       /* assign Capture Source enums to NID */
+       if (spec->capsrc_nids || spec->adc_nids) {
+               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++) {
+                       const hda_nid_t *nids = spec->capsrc_nids;
+                       if (!nids)
+                               nids = spec->adc_nids;
+                       err = snd_hda_add_nid(codec, kctl, i, nids[i]);
+                       if (err < 0)
+                               return err;
+               }
+       }
+       if (spec->cap_mixer) {
+               const char *kname = kctl ? kctl->id.name : NULL;
+               for (knew = spec->cap_mixer; knew->name; knew++) {
+                       if (kname && strcmp(knew->name, kname) == 0)
+                               continue;
+                       kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+                       for (i = 0; kctl && i < kctl->count; i++) {
+                               err = snd_hda_add_nid(codec, kctl, i,
+                                                     spec->adc_nids[i]);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
 
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x17;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
+       /* other nid->control mapping */
+       for (i = 0; i < spec->num_mixers; i++) {
+               for (knew = spec->mixers[i]; knew->name; knew++) {
+                       if (knew->iface != NID_MAPPING)
+                               continue;
+                       kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+                       if (kctl == NULL)
+                               continue;
+                       u = knew->subdevice;
+                       for (j = 0; j < 4; j++, u >>= 8) {
+                               nid = u & 0x3f;
+                               if (nid == 0)
+                                       continue;
+                               switch (u & 0xc0) {
+                               case SUBDEV_SPEAKER_:
+                                       nid = spec->autocfg.speaker_pins[nid];
+                                       break;
+                               case SUBDEV_LINE_:
+                                       nid = spec->autocfg.line_out_pins[nid];
+                                       break;
+                               case SUBDEV_HP_:
+                                       nid = spec->autocfg.hp_pins[nid];
+                                       break;
+                               default:
+                                       continue;
+                               }
+                               err = snd_hda_add_nid(codec, kctl, 0, nid);
+                               if (err < 0)
+                                       return err;
+                       }
+                       u = knew->private_value;
+                       for (j = 0; j < 4; j++, u >>= 8) {
+                               nid = u & 0xff;
+                               if (nid == 0)
+                                       continue;
+                               err = snd_hda_add_nid(codec, kctl, 0, nid);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
 
-static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
+       alc_free_kctls(codec); /* no longer needed */
 
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x1b;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
+       return 0;
 }
 
+
 /*
- * ALC880 3-stack model
- *
- * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
- * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
- *                 F-Mic = 0x1b, HP = 0x19
+ * Common callbacks
  */
 
-static const hda_nid_t alc880_dac_nids[4] = {
-       /* front, rear, clfe, rear_surr */
-       0x02, 0x05, 0x04, 0x03
-};
+static void alc_init_special_input_src(struct hda_codec *codec);
 
-static const hda_nid_t alc880_adc_nids[3] = {
-       /* ADC0-2 */
-       0x07, 0x08, 0x09,
-};
+static int alc_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int i;
 
-/* The datasheet says the node 0x07 is connected from inputs,
- * but it shows zero connection in the real implementation on some devices.
- * Note: this is a 915GAV bug, fixed on 915GLV
- */
-static const hda_nid_t alc880_adc_nids_alt[2] = {
-       /* ADC1-2 */
-       0x08, 0x09,
-};
+       alc_fix_pll(codec);
+       alc_auto_init_amp(codec, spec->init_amp);
 
-#define ALC880_DIGOUT_NID      0x06
-#define ALC880_DIGIN_NID       0x0a
-
-static const struct hda_input_mux alc880_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x3 },
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-/* channel source setting (2/6 channel selection for 3-stack) */
-/* 2ch mode */
-static const struct hda_verb alc880_threestack_ch2_init[] = {
-       /* set line-in to input, mute it */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       /* set mic-in to input vref 80%, mute it */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
+       for (i = 0; i < spec->num_init_verbs; i++)
+               snd_hda_sequence_write(codec, spec->init_verbs[i]);
+       alc_init_special_input_src(codec);
 
-/* 6ch mode */
-static const struct hda_verb alc880_threestack_ch6_init[] = {
-       /* set line-in to output, unmute it */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       /* set mic-in to output, unmute it */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { } /* end */
-};
+       if (spec->init_hook)
+               spec->init_hook(codec);
 
-static const struct hda_channel_mode alc880_threestack_modes[2] = {
-       { 2, alc880_threestack_ch2_init },
-       { 6, alc880_threestack_ch6_init },
-};
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
 
-static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
+       hda_call_check_power_status(codec, 0x01);
+       return 0;
+}
 
-/* capture mixer elements */
-static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_info *uinfo)
+static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
-       int err;
 
-       mutex_lock(&codec->control_mutex);
-       kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
-                                                     HDA_INPUT);
-       err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
-       mutex_unlock(&codec->control_mutex);
-       return err;
+       if (spec->unsol_event)
+               spec->unsol_event(codec, res);
 }
 
-static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
-                          unsigned int size, unsigned int __user *tlv)
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
-       int err;
-
-       mutex_lock(&codec->control_mutex);
-       kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
-                                                     HDA_INPUT);
-       err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
-       mutex_unlock(&codec->control_mutex);
-       return err;
+       return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
 }
+#endif
 
-typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol);
-
-static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol,
-                                getput_call_t func, bool check_adc_switch)
+/*
+ * Analog playback callbacks
+ */
+static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
-       int i, err = 0;
-
-       mutex_lock(&codec->control_mutex);
-       if (check_adc_switch && spec->dual_adc_switch) {
-               for (i = 0; i < spec->num_adc_nids; i++) {
-                       kcontrol->private_value =
-                               HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
-                                                   3, 0, HDA_INPUT);
-                       err = func(kcontrol, ucontrol);
-                       if (err < 0)
-                               goto error;
-               }
-       } else {
-               i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-               kcontrol->private_value =
-                       HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
-                                           3, 0, HDA_INPUT);
-               err = func(kcontrol, ucontrol);
-       }
- error:
-       mutex_unlock(&codec->control_mutex);
-       return err;
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
 }
 
-static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
+static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      unsigned int stream_tag,
+                                      unsigned int format,
+                                      struct snd_pcm_substream *substream)
 {
-       return alc_cap_getput_caller(kcontrol, ucontrol,
-                                    snd_hda_mixer_amp_volume_get, false);
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+                                               stream_tag, format, substream);
 }
 
-static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
+static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      struct snd_pcm_substream *substream)
 {
-       return alc_cap_getput_caller(kcontrol, ucontrol,
-                                    snd_hda_mixer_amp_volume_put, true);
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
 }
 
-/* capture mixer elements */
-#define alc_cap_sw_info                snd_ctl_boolean_stereo_info
-
-static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
+/*
+ * Digital out
+ */
+static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       struct snd_pcm_substream *substream)
 {
-       return alc_cap_getput_caller(kcontrol, ucontrol,
-                                    snd_hda_mixer_amp_switch_get, false);
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
 }
 
-static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
+static int alc_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)
 {
-       return alc_cap_getput_caller(kcontrol, ucontrol,
-                                    snd_hda_mixer_amp_switch_put, true);
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+                                            stream_tag, format, substream);
 }
 
-#define _DEFINE_CAPMIX(num) \
-       { \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-               .name = "Capture Switch", \
-               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
-               .count = num, \
-               .info = alc_cap_sw_info, \
-               .get = alc_cap_sw_get, \
-               .put = alc_cap_sw_put, \
-       }, \
-       { \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-               .name = "Capture Volume", \
-               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
-                          SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
-                          SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
-               .count = num, \
-               .info = alc_cap_vol_info, \
-               .get = alc_cap_vol_get, \
-               .put = alc_cap_vol_put, \
-               .tlv = { .c = alc_cap_vol_tlv }, \
-       }
-
-#define _DEFINE_CAPSRC(num) \
-       { \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-               /* .name = "Capture Source", */ \
-               .name = "Input Source", \
-               .count = num, \
-               .info = alc_mux_enum_info, \
-               .get = alc_mux_enum_get, \
-               .put = alc_mux_enum_put, \
-       }
-
-#define DEFINE_CAPMIX(num) \
-static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
-       _DEFINE_CAPMIX(num),                                  \
-       _DEFINE_CAPSRC(num),                                  \
-       { } /* end */                                         \
+static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                          struct hda_codec *codec,
+                                          struct snd_pcm_substream *substream)
+{
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
 }
 
-#define DEFINE_CAPMIX_NOSRC(num) \
-static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
-       _DEFINE_CAPMIX(num),                                        \
-       { } /* end */                                               \
+static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                        struct hda_codec *codec,
+                                        struct snd_pcm_substream *substream)
+{
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
-/* up to three ADCs */
-DEFINE_CAPMIX(1);
-DEFINE_CAPMIX(2);
-DEFINE_CAPMIX(3);
-DEFINE_CAPMIX_NOSRC(1);
-DEFINE_CAPMIX_NOSRC(2);
-DEFINE_CAPMIX_NOSRC(3);
-
 /*
- * ALC880 5-stack model
- *
- * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
- *      Side = 0x02 (0xd)
- * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
- *                 Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
+ * Analog capture
  */
+static int alc_alt_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 alc_spec *spec = codec->spec;
 
-/* additional mixers to alc880_three_stack_mixer */
-static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
-       { } /* end */
-};
+       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
+                                  stream_tag, 0, format);
+       return 0;
+}
 
-/* channel source setting (6/8 channel selection for 5-stack) */
-/* 6ch mode */
-static const struct hda_verb alc880_fivestack_ch6_init[] = {
-       /* set line-in to input, mute it */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
+static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                     struct hda_codec *codec,
+                                     struct snd_pcm_substream *substream)
+{
+       struct alc_spec *spec = codec->spec;
 
-/* 8ch mode */
-static const struct hda_verb alc880_fivestack_ch8_init[] = {
-       /* set line-in to output, unmute it */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { } /* end */
-};
+       snd_hda_codec_cleanup_stream(codec,
+                                    spec->adc_nids[substream->number + 1]);
+       return 0;
+}
 
-static const struct hda_channel_mode alc880_fivestack_modes[2] = {
-       { 6, alc880_fivestack_ch6_init },
-       { 8, alc880_fivestack_ch8_init },
-};
+/* analog capture with dynamic dual-adc changes */
+static int dyn_adc_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 alc_spec *spec = codec->spec;
+       spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
+       spec->cur_adc_stream_tag = stream_tag;
+       spec->cur_adc_format = format;
+       snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
+       return 0;
+}
+
+static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      struct snd_pcm_substream *substream)
+{
+       struct alc_spec *spec = codec->spec;
+       snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+       spec->cur_adc = 0;
+       return 0;
+}
 
+static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0, /* fill later */
+       .ops = {
+               .prepare = dyn_adc_capture_pcm_prepare,
+               .cleanup = dyn_adc_capture_pcm_cleanup
+       },
+};
 
 /*
- * ALC880 6-stack model
- *
- * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
- *      Side = 0x05 (0x0f)
- * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
- *   Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
  */
-
-static const hda_nid_t alc880_6st_dac_nids[4] = {
-       /* front, rear, clfe, rear_surr */
-       0x02, 0x03, 0x04, 0x05
+static const struct hda_pcm_stream alc_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       /* NID is set in alc_build_pcms */
+       .ops = {
+               .open = alc_playback_pcm_open,
+               .prepare = alc_playback_pcm_prepare,
+               .cleanup = alc_playback_pcm_cleanup
+       },
 };
 
-static const struct hda_input_mux alc880_6stack_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-       },
+static const struct hda_pcm_stream alc_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in alc_build_pcms */
 };
 
-/* fixed 8-channels */
-static const struct hda_channel_mode alc880_sixstack_modes[1] = {
-       { 8, NULL },
+static const struct hda_pcm_stream alc_pcm_analog_alt_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in alc_build_pcms */
 };
 
-static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
+static const struct hda_pcm_stream alc_pcm_analog_alt_capture = {
+       .substreams = 2, /* can be overridden */
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in alc_build_pcms */
+       .ops = {
+               .prepare = alc_alt_capture_pcm_prepare,
+               .cleanup = alc_alt_capture_pcm_cleanup
        },
-       { } /* end */
 };
 
-
-/*
- * ALC880 W810 model
- *
- * W810 has rear IO for:
- * Front (DAC 02)
- * Surround (DAC 03)
- * Center/LFE (DAC 04)
- * Digital out (06)
- *
- * The system also has a pair of internal speakers, and a headphone jack.
- * These are both connected to Line2 on the codec, hence to DAC 02.
- *
- * There is a variable resistor to control the speaker or headphone
- * volume. This is a hardware-only device without a software API.
- *
- * Plugging headphones in will disable the internal speakers. This is
- * implemented in hardware, not via the driver using jack sense. In
- * a similar fashion, plugging into the rear socket marked "front" will
- * disable both the speakers and headphones.
- *
- * For input, there's a microphone jack, and an "audio in" jack.
- * These may not do anything useful with this driver yet, because I
- * haven't setup any initialization verbs for these yet...
- */
-
-static const hda_nid_t alc880_w810_dac_nids[3] = {
-       /* front, rear/surround, clfe */
-       0x02, 0x03, 0x04
+static const struct hda_pcm_stream alc_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in alc_build_pcms */
+       .ops = {
+               .open = alc_dig_playback_pcm_open,
+               .close = alc_dig_playback_pcm_close,
+               .prepare = alc_dig_playback_pcm_prepare,
+               .cleanup = alc_dig_playback_pcm_cleanup
+       },
 };
 
-/* fixed 6 channels */
-static const struct hda_channel_mode alc880_w810_modes[1] = {
-       { 6, NULL }
+static const struct hda_pcm_stream alc_pcm_digital_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in alc_build_pcms */
 };
 
-/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
-static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       { } /* end */
+/* Used by alc_build_pcms to flag that a PCM has no playback stream */
+static const struct hda_pcm_stream alc_pcm_null_stream = {
+       .substreams = 0,
+       .channels_min = 0,
+       .channels_max = 0,
 };
 
+static int alc_build_pcms(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct hda_pcm *info = spec->pcm_rec;
+       const struct hda_pcm_stream *p;
+       int i;
 
-/*
- * Z710V model
- *
- * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
- * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
- *                 Line = 0x1a
- */
+       codec->num_pcms = 1;
+       codec->pcm_info = info;
 
-static const hda_nid_t alc880_z71v_dac_nids[1] = {
-       0x02
-};
-#define ALC880_Z71V_HP_DAC     0x03
+       if (spec->no_analog)
+               goto skip_analog;
 
-/* fixed 2 channels */
-static const struct hda_channel_mode alc880_2_jack_modes[1] = {
-       { 2, NULL }
-};
+       snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
+                "%s Analog", codec->chip_name);
+       info->name = spec->stream_name_analog;
 
-static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
+       if (spec->multiout.dac_nids > 0) {
+               p = spec->stream_analog_playback;
+               if (!p)
+                       p = &alc_pcm_analog_playback;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+       }
+       if (spec->adc_nids) {
+               p = spec->stream_analog_capture;
+               if (!p) {
+                       if (spec->dyn_adc_switch)
+                               p = &dyn_adc_pcm_analog_capture;
+                       else
+                               p = &alc_pcm_analog_capture;
+               }
+               info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
+               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+       }
 
+       if (spec->channel_mode) {
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
+               for (i = 0; i < spec->num_channel_mode; i++) {
+                       if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
+                               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
+                       }
+               }
+       }
 
-/*
- * ALC880 F1734 model
- *
- * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
- * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
- */
+ skip_analog:
+       /* SPDIF for stream index #1 */
+       if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+               snprintf(spec->stream_name_digital,
+                        sizeof(spec->stream_name_digital),
+                        "%s Digital", codec->chip_name);
+               codec->num_pcms = 2;
+               codec->slave_dig_outs = spec->multiout.slave_dig_outs;
+               info = spec->pcm_rec + 1;
+               info->name = spec->stream_name_digital;
+               if (spec->dig_out_type)
+                       info->pcm_type = spec->dig_out_type;
+               else
+                       info->pcm_type = HDA_PCM_TYPE_SPDIF;
+               if (spec->multiout.dig_out_nid) {
+                       p = spec->stream_digital_playback;
+                       if (!p)
+                               p = &alc_pcm_digital_playback;
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
+               }
+               if (spec->dig_in_nid) {
+                       p = spec->stream_digital_capture;
+                       if (!p)
+                               p = &alc_pcm_digital_capture;
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
+               }
+               /* FIXME: do we need this for all Realtek codec models? */
+               codec->spdif_status_reset = 1;
+       }
 
-static const hda_nid_t alc880_f1734_dac_nids[1] = {
-       0x03
-};
-#define ALC880_F1734_HP_DAC    0x02
-
-static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
+       if (spec->no_analog)
+               return 0;
 
-static const struct hda_input_mux alc880_f1734_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x1 },
-               { "CD", 0x4 },
-       },
-};
+       /* If the use of more than one ADC is requested for the current
+        * model, configure a second analog capture-only PCM.
+        */
+       /* Additional Analaog capture for index #2 */
+       if (spec->alt_dac_nid || spec->num_adc_nids > 1) {
+               codec->num_pcms = 3;
+               info = spec->pcm_rec + 2;
+               info->name = spec->stream_name_analog;
+               if (spec->alt_dac_nid) {
+                       p = spec->stream_analog_alt_playback;
+                       if (!p)
+                               p = &alc_pcm_analog_alt_playback;
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+                               spec->alt_dac_nid;
+               } else {
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+                               alc_pcm_null_stream;
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
+               }
+               if (spec->num_adc_nids > 1) {
+                       p = spec->stream_analog_alt_capture;
+                       if (!p)
+                               p = &alc_pcm_analog_alt_capture;
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+                               spec->adc_nids[1];
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
+                               spec->num_adc_nids - 1;
+               } else {
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                               alc_pcm_null_stream;
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
+               }
+       }
 
+       return 0;
+}
 
-/*
- * ALC880 ASUS model
- *
- * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
- * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
- *  Mic = 0x18, Line = 0x1a
- */
+static inline void alc_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
 
-#define alc880_asus_dac_nids   alc880_w810_dac_nids    /* identical with w810 */
-#define alc880_asus_modes      alc880_threestack_modes /* 2/6 channel mode */
-
-static const struct snd_kcontrol_new alc880_asus_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
+       if (spec && spec->shutup)
+               spec->shutup(codec);
+       snd_hda_shutup_pins(codec);
+}
 
-/*
- * ALC880 ASUS W1V model
- *
- * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
- * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
- *  Mic = 0x18, Line = 0x1a, Line2 = 0x1b
- */
+static void alc_free_kctls(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
 
-/* additional mixers to alc880_asus_mixer */
-static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
-       HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
-       { } /* end */
-};
+       if (spec->kctls.list) {
+               struct snd_kcontrol_new *kctl = spec->kctls.list;
+               int i;
+               for (i = 0; i < spec->kctls.used; i++)
+                       kfree(kctl[i].name);
+       }
+       snd_array_free(&spec->kctls);
+}
 
-/* TCL S700 */
-static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-       { } /* end */
-};
+static void alc_free(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
 
-/* Uniwill */
-static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
+       if (!spec)
+               return;
 
-static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
+       alc_shutup(codec);
+       snd_hda_input_jack_free(codec);
+       alc_free_kctls(codec);
+       kfree(spec);
+       snd_hda_detach_beep_device(codec);
+}
 
-static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static void alc_power_eapd(struct hda_codec *codec)
+{
+       alc_auto_setup_eapd(codec, false);
+}
 
-/*
- * virtual master controls
- */
+static int alc_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       struct alc_spec *spec = codec->spec;
+       alc_shutup(codec);
+       if (spec && spec->power_hook)
+               spec->power_hook(codec);
+       return 0;
+}
+#endif
+
+#ifdef SND_HDA_NEEDS_RESUME
+static int alc_resume(struct hda_codec *codec)
+{
+       msleep(150); /* to avoid pop noise */
+       codec->patch_ops.init(codec);
+       snd_hda_codec_resume_amp(codec);
+       snd_hda_codec_resume_cache(codec);
+       hda_call_check_power_status(codec, 0x01);
+       return 0;
+}
+#endif
 
 /*
- * slave controls for virtual master
  */
-static const char * const alc_slave_vols[] = {
-       "Front Playback Volume",
-       "Surround Playback Volume",
-       "Center Playback Volume",
-       "LFE Playback Volume",
-       "Side Playback Volume",
-       "Headphone Playback Volume",
-       "Speaker Playback Volume",
-       "Mono Playback Volume",
-       "Line-Out Playback Volume",
-       NULL,
+static const struct hda_codec_ops alc_patch_ops = {
+       .build_controls = alc_build_controls,
+       .build_pcms = alc_build_pcms,
+       .init = alc_init,
+       .free = alc_free,
+       .unsol_event = alc_unsol_event,
+#ifdef SND_HDA_NEEDS_RESUME
+       .resume = alc_resume,
+#endif
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       .suspend = alc_suspend,
+       .check_power_status = alc_check_power_status,
+#endif
+       .reboot_notify = alc_shutup,
 };
 
-static const char * const alc_slave_sws[] = {
-       "Front Playback Switch",
-       "Surround Playback Switch",
-       "Center Playback Switch",
-       "LFE Playback Switch",
-       "Side Playback Switch",
-       "Headphone Playback Switch",
-       "Speaker Playback Switch",
-       "Mono Playback Switch",
-       "IEC958 Playback Switch",
-       "Line-Out Playback Switch",
-       NULL,
-};
+/* replace the codec chip_name with the given string */
+static int alc_codec_rename(struct hda_codec *codec, const char *name)
+{
+       kfree(codec->chip_name);
+       codec->chip_name = kstrdup(name, GFP_KERNEL);
+       if (!codec->chip_name) {
+               alc_free(codec);
+               return -ENOMEM;
+       }
+       return 0;
+}
 
 /*
- * build control elements
+ * Automatic parse of I/O pins from the BIOS configuration
  */
 
-#define NID_MAPPING            (-1)
-
-#define SUBDEV_SPEAKER_                (0 << 6)
-#define SUBDEV_HP_             (1 << 6)
-#define SUBDEV_LINE_           (2 << 6)
-#define SUBDEV_SPEAKER(x)      (SUBDEV_SPEAKER_ | ((x) & 0x3f))
-#define SUBDEV_HP(x)           (SUBDEV_HP_ | ((x) & 0x3f))
-#define SUBDEV_LINE(x)         (SUBDEV_LINE_ | ((x) & 0x3f))
-
-static void alc_free_kctls(struct hda_codec *codec);
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-/* additional beep mixers; the actual parameters are overwritten at build */
-static const struct snd_kcontrol_new alc_beep_mixer[] = {
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
-       HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
-       { } /* end */
-};
-#endif
-
-static int alc_build_controls(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct snd_kcontrol *kctl = NULL;
-       const struct snd_kcontrol_new *knew;
-       int i, j, err;
-       unsigned int u;
-       hda_nid_t nid;
-
-       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->cap_mixer) {
-               err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
-               if (err < 0)
-                       return err;
-       }
-       if (spec->multiout.dig_out_nid) {
-               err = snd_hda_create_spdif_out_ctls(codec,
-                                                   spec->multiout.dig_out_nid);
-               if (err < 0)
-                       return err;
-               if (!spec->no_analog) {
-                       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;
-       }
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-       /* create beep controls if needed */
-       if (spec->beep_amp) {
-               const struct snd_kcontrol_new *knew;
-               for (knew = alc_beep_mixer; knew->name; knew++) {
-                       struct snd_kcontrol *kctl;
-                       kctl = snd_ctl_new1(knew, codec);
-                       if (!kctl)
-                               return -ENOMEM;
-                       kctl->private_value = spec->beep_amp;
-                       err = snd_hda_ctl_add(codec, 0, kctl);
-                       if (err < 0)
-                               return err;
-               }
-       }
-#endif
-
-       /* if we have no master control, let's create it */
-       if (!spec->no_analog &&
-           !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, alc_slave_vols);
-               if (err < 0)
-                       return err;
-       }
-       if (!spec->no_analog &&
-           !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
-               err = snd_hda_add_vmaster(codec, "Master Playback Switch",
-                                         NULL, alc_slave_sws);
-               if (err < 0)
-                       return err;
-       }
-
-       /* assign Capture Source enums to NID */
-       if (spec->capsrc_nids || spec->adc_nids) {
-               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++) {
-                       const hda_nid_t *nids = spec->capsrc_nids;
-                       if (!nids)
-                               nids = spec->adc_nids;
-                       err = snd_hda_add_nid(codec, kctl, i, nids[i]);
-                       if (err < 0)
-                               return err;
-               }
-       }
-       if (spec->cap_mixer) {
-               const char *kname = kctl ? kctl->id.name : NULL;
-               for (knew = spec->cap_mixer; knew->name; knew++) {
-                       if (kname && strcmp(knew->name, kname) == 0)
-                               continue;
-                       kctl = snd_hda_find_mixer_ctl(codec, knew->name);
-                       for (i = 0; kctl && i < kctl->count; i++) {
-                               err = snd_hda_add_nid(codec, kctl, i,
-                                                     spec->adc_nids[i]);
-                               if (err < 0)
-                                       return err;
-                       }
-               }
-       }
-
-       /* other nid->control mapping */
-       for (i = 0; i < spec->num_mixers; i++) {
-               for (knew = spec->mixers[i]; knew->name; knew++) {
-                       if (knew->iface != NID_MAPPING)
-                               continue;
-                       kctl = snd_hda_find_mixer_ctl(codec, knew->name);
-                       if (kctl == NULL)
-                               continue;
-                       u = knew->subdevice;
-                       for (j = 0; j < 4; j++, u >>= 8) {
-                               nid = u & 0x3f;
-                               if (nid == 0)
-                                       continue;
-                               switch (u & 0xc0) {
-                               case SUBDEV_SPEAKER_:
-                                       nid = spec->autocfg.speaker_pins[nid];
-                                       break;
-                               case SUBDEV_LINE_:
-                                       nid = spec->autocfg.line_out_pins[nid];
-                                       break;
-                               case SUBDEV_HP_:
-                                       nid = spec->autocfg.hp_pins[nid];
-                                       break;
-                               default:
-                                       continue;
-                               }
-                               err = snd_hda_add_nid(codec, kctl, 0, nid);
-                               if (err < 0)
-                                       return err;
-                       }
-                       u = knew->private_value;
-                       for (j = 0; j < 4; j++, u >>= 8) {
-                               nid = u & 0xff;
-                               if (nid == 0)
-                                       continue;
-                               err = snd_hda_add_nid(codec, kctl, 0, nid);
-                               if (err < 0)
-                                       return err;
-                       }
-               }
-       }
-
-       alc_free_kctls(codec); /* no longer needed */
-
-       return 0;
-}
-
-
-/*
- * initialize the codec volumes, etc
- */
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc880_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for front
-        * panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-
-       /*
-        * Set up output mixers (0x0c - 0x0f)
-        */
-       /* set vol=0 to output mixers */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-       { }
-};
-
-/*
- * 3-stack pin configuration:
- * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
- */
-static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
-       /*
-        * preset connection lists of input pins
-        * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
-        */
-       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
-
-       /*
-        * Set pin mode and muting
-        */
-       /* set front pin widgets 0x14 for output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Mic1 (rear panel) pin widget for input and vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mic2 (as headphone out) for HP output */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Line In pin widget for input */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line2 (as front mic) pin widget for input and vref at 80% */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* CD pin widget for input */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       { }
-};
-
-/*
- * 5-stack pin configuration:
- * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
- * line-in/side = 0x1a, f-mic = 0x1b
- */
-static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
-       /*
-        * preset connection lists of input pins
-        * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
-        */
-       {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
-
-       /*
-        * Set pin mode and muting
-        */
-       /* set pin widgets 0x14-0x17 for output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* unmute pins for output (no gain on this amp) */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Mic1 (rear panel) pin widget for input and vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mic2 (as headphone out) for HP output */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Line In pin widget for input */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line2 (as front mic) pin widget for input and vref at 80% */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* CD pin widget for input */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       { }
-};
-
-/*
- * W810 pin configuration:
- * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
- */
-static const struct hda_verb alc880_pin_w810_init_verbs[] = {
-       /* hphone/speaker input selector: front DAC */
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       { }
-};
-
-/*
- * Z71V pin configuration:
- * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
- */
-static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       { }
-};
-
-/*
- * 6-stack pin configuration:
- * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
- * f-mic = 0x19, line = 0x1a, HP = 0x1b
- */
-static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       { }
-};
-
-/*
- * Uniwill pin configuration:
- * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
- * line = 0x1a
- */
-static const struct hda_verb alc880_uniwill_init_verbs[] = {
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
-       /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-
-       { }
-};
-
-/*
-* Uniwill P53
-* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
- */
-static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
-
-       { }
-};
-
-static const struct hda_verb alc880_beep_init_verbs[] = {
-       { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
-       { }
-};
-
-/* auto-toggle front mic */
-static void alc88x_simple_mic_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-       unsigned char bits;
-
-       present = snd_hda_jack_detect(codec, 0x18);
-       bits = present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
-}
-
-static void alc880_uniwill_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x16;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc880_uniwill_init_hook(struct hda_codec *codec)
-{
-       alc_hp_automute(codec);
-       alc88x_simple_mic_automute(codec);
-}
-
-static void alc880_uniwill_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
-{
-       /* Looks like the unsol event is incompatible with the standard
-        * definition.  4bit tag is placed at 28 bit!
-        */
-       switch (res >> 28) {
-       case ALC880_MIC_EVENT:
-               alc88x_simple_mic_automute(codec);
-               break;
-       default:
-               alc_sku_unsol_event(codec, res);
-               break;
-       }
-}
-
-static void alc880_uniwill_p53_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_codec_read(codec, 0x21, 0,
-                                    AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
-       present &= HDA_AMP_VOLMASK;
-       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
-                                HDA_AMP_VOLMASK, present);
-       snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
-                                HDA_AMP_VOLMASK, present);
-}
-
-static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
-                                          unsigned int res)
-{
-       /* Looks like the unsol event is incompatible with the standard
-        * definition.  4bit tag is placed at 28 bit!
-        */
-       if ((res >> 28) == ALC880_DCVOL_EVENT)
-               alc880_uniwill_p53_dcvol_automute(codec);
-       else
-               alc_sku_unsol_event(codec, res);
-}
-
-/*
- * F1734 pin configuration:
- * HP = 0x14, speaker-out = 0x15, mic = 0x18
- */
-static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
-       {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
-
-       { }
-};
-
-/*
- * ASUS pin configuration:
- * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
- */
-static const struct hda_verb alc880_pin_asus_init_verbs[] = {
-       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
-       {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       { }
-};
-
-/* Enable GPIO mask and set output */
-#define alc880_gpio1_init_verbs        alc_gpio1_init_verbs
-#define alc880_gpio2_init_verbs        alc_gpio2_init_verbs
-#define alc880_gpio3_init_verbs        alc_gpio3_init_verbs
-
-/* Clevo m520g init */
-static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
-       /* headphone output */
-       {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* line-out */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Line-in */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* CD */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Mic1 (rear panel) */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Mic2 (front panel) */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* headphone */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-        /* change to EAPD mode */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x3060},
-
-       { }
-};
-
-static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
-       /* change to EAPD mode */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x3060},
-
-       /* Headphone output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Front output*/
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Line In pin widget for input */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* CD pin widget for input */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* Mic1 (rear panel) pin widget for input and vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-
-       /* change to EAPD mode */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x3070},
-
-       { }
-};
-
-/*
- * LG m1 express dual
- *
- * Pin assignment:
- *   Rear Line-In/Out (blue): 0x14
- *   Build-in Mic-In: 0x15
- *   Speaker-out: 0x17
- *   HP-Out (green): 0x1b
- *   Mic-In/Out (red): 0x19
- *   SPDIF-Out: 0x1e
- */
-
-/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
-static const hda_nid_t alc880_lg_dac_nids[3] = {
-       0x05, 0x02, 0x03
-};
-
-/* seems analog CD is not working */
-static const struct hda_input_mux alc880_lg_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x1 },
-               { "Line", 0x5 },
-               { "Internal Mic", 0x6 },
-       },
-};
-
-/* 2,4,6 channel modes */
-static const struct hda_verb alc880_lg_ch2_init[] = {
-       /* set line-in and mic-in to input */
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { }
-};
-
-static const struct hda_verb alc880_lg_ch4_init[] = {
-       /* set line-in to out and mic-in to input */
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { }
-};
-
-static const struct hda_verb alc880_lg_ch6_init[] = {
-       /* set line-in and mic-in to output */
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-       { }
-};
-
-static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
-       { 2, alc880_lg_ch2_init },
-       { 4, alc880_lg_ch4_init },
-       { 6, alc880_lg_ch6_init },
-};
-
-static const struct snd_kcontrol_new alc880_lg_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb alc880_lg_init_verbs[] = {
-       /* set capture source to mic-in */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* mute all amp mixer inputs */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* line-in to input */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* built-in mic */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* speaker-out */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* mic-in to input */
-       {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* HP-out */
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* jack sense */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x17;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/*
- * LG LW20
- *
- * Pin assignment:
- *   Speaker-out: 0x14
- *   Mic-In: 0x18
- *   Built-in Mic-In: 0x19
- *   Line-In: 0x1b
- *   HP-Out: 0x1a
- *   SPDIF-Out: 0x1e
- */
-
-static const struct hda_input_mux alc880_lg_lw_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-               { "Line In", 0x2 },
-       },
-};
-
-#define alc880_lg_lw_modes alc880_threestack_modes
-
-static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb alc880_lg_lw_init_verbs[] = {
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
-
-       /* set capture source to mic-in */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* speaker-out */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* HP-out */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* mic-in to input */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* built-in mic */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* jack sense */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_lw_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_input_mux alc880_medion_rim_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-       },
-};
-
-static const struct hda_verb alc880_medion_rim_init_verbs[] = {
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Mic1 (rear panel) pin widget for input and vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mic2 (as headphone out) for HP output */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Internal Speaker */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x3060},
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_medion_rim_automute(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_hp_automute(codec);
-       /* toggle EAPD */
-       if (spec->jack_present)
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
-       else
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
-}
-
-static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
-                                         unsigned int res)
-{
-       /* Looks like the unsol event is incompatible with the standard
-        * definition.  4bit tag is placed at 28 bit!
-        */
-       if ((res >> 28) == ALC880_HP_EVENT)
-               alc880_medion_rim_automute(codec);
-}
-
-static void alc880_medion_rim_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x1b;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc880_loopbacks[] = {
-       { 0x0b, HDA_INPUT, 0 },
-       { 0x0b, HDA_INPUT, 1 },
-       { 0x0b, HDA_INPUT, 2 },
-       { 0x0b, HDA_INPUT, 3 },
-       { 0x0b, HDA_INPUT, 4 },
-       { } /* end */
-};
-
-static const struct hda_amp_list alc880_lg_loopbacks[] = {
-       { 0x0b, HDA_INPUT, 1 },
-       { 0x0b, HDA_INPUT, 6 },
-       { 0x0b, HDA_INPUT, 7 },
-       { } /* end */
-};
-#endif
-
-/*
- * Common callbacks
- */
-
-static void alc_init_special_input_src(struct hda_codec *codec);
-
-static int alc_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       unsigned int i;
-
-       alc_fix_pll(codec);
-       alc_auto_init_amp(codec, spec->init_amp);
-
-       for (i = 0; i < spec->num_init_verbs; i++)
-               snd_hda_sequence_write(codec, spec->init_verbs[i]);
-       alc_init_special_input_src(codec);
-
-       if (spec->init_hook)
-               spec->init_hook(codec);
-
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
-
-       hda_call_check_power_status(codec, 0x01);
-       return 0;
-}
-
-static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec->unsol_event)
-               spec->unsol_event(codec, res);
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct alc_spec *spec = codec->spec;
-       return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
-}
-#endif
-
-/*
- * Analog playback callbacks
- */
-static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   struct snd_pcm_substream *substream)
-{
-       struct alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
-                                            hinfo);
-}
-
-static int alc880_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 alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
-                                               stream_tag, format, substream);
-}
-
-static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                      struct hda_codec *codec,
-                                      struct snd_pcm_substream *substream)
-{
-       struct alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
-
-/*
- * Digital out
- */
-static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int alc880_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 alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
-                                            stream_tag, format, substream);
-}
-
-static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                          struct hda_codec *codec,
-                                          struct snd_pcm_substream *substream)
-{
-       struct alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
-}
-
-static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                        struct hda_codec *codec,
-                                        struct snd_pcm_substream *substream)
-{
-       struct alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-/*
- * Analog capture
- */
-static int alc880_alt_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 alc_spec *spec = codec->spec;
-
-       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
-                                  stream_tag, 0, format);
-       return 0;
-}
-
-static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                     struct hda_codec *codec,
-                                     struct snd_pcm_substream *substream)
-{
-       struct alc_spec *spec = codec->spec;
-
-       snd_hda_codec_cleanup_stream(codec,
-                                    spec->adc_nids[substream->number + 1]);
-       return 0;
-}
-
-/* analog capture with dynamic dual-adc changes */
-static int dualmic_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 alc_spec *spec = codec->spec;
-       spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
-       spec->cur_adc_stream_tag = stream_tag;
-       spec->cur_adc_format = format;
-       snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
-       return 0;
-}
-
-static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                      struct hda_codec *codec,
-                                      struct snd_pcm_substream *substream)
-{
-       struct alc_spec *spec = codec->spec;
-       snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
-       spec->cur_adc = 0;
-       return 0;
-}
-
-static const struct hda_pcm_stream dualmic_pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0, /* fill later */
-       .ops = {
-               .prepare = dualmic_capture_pcm_prepare,
-               .cleanup = dualmic_capture_pcm_cleanup
-       },
-};
-
-/*
- */
-static const struct hda_pcm_stream alc880_pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 8,
-       /* NID is set in alc_build_pcms */
-       .ops = {
-               .open = alc880_playback_pcm_open,
-               .prepare = alc880_playback_pcm_prepare,
-               .cleanup = alc880_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream alc880_pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in alc_build_pcms */
-};
-
-static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in alc_build_pcms */
-};
-
-static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
-       .substreams = 2, /* can be overridden */
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in alc_build_pcms */
-       .ops = {
-               .prepare = alc880_alt_capture_pcm_prepare,
-               .cleanup = alc880_alt_capture_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream alc880_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in alc_build_pcms */
-       .ops = {
-               .open = alc880_dig_playback_pcm_open,
-               .close = alc880_dig_playback_pcm_close,
-               .prepare = alc880_dig_playback_pcm_prepare,
-               .cleanup = alc880_dig_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream alc880_pcm_digital_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in alc_build_pcms */
-};
-
-/* Used by alc_build_pcms to flag that a PCM has no playback stream */
-static const struct hda_pcm_stream alc_pcm_null_stream = {
-       .substreams = 0,
-       .channels_min = 0,
-       .channels_max = 0,
-};
-
-static int alc_build_pcms(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-       int i;
-
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       if (spec->no_analog)
-               goto skip_analog;
-
-       snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
-                "%s Analog", codec->chip_name);
-       info->name = spec->stream_name_analog;
-
-       if (spec->stream_analog_playback) {
-               if (snd_BUG_ON(!spec->multiout.dac_nids))
-                       return -EINVAL;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
-       }
-       if (spec->stream_analog_capture) {
-               if (snd_BUG_ON(!spec->adc_nids))
-                       return -EINVAL;
-               info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
-               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
-       }
-
-       if (spec->channel_mode) {
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
-               for (i = 0; i < spec->num_channel_mode; i++) {
-                       if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
-                               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
-                       }
-               }
-       }
-
- skip_analog:
-       /* SPDIF for stream index #1 */
-       if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
-               snprintf(spec->stream_name_digital,
-                        sizeof(spec->stream_name_digital),
-                        "%s Digital", codec->chip_name);
-               codec->num_pcms = 2;
-               codec->slave_dig_outs = spec->multiout.slave_dig_outs;
-               info = spec->pcm_rec + 1;
-               info->name = spec->stream_name_digital;
-               if (spec->dig_out_type)
-                       info->pcm_type = spec->dig_out_type;
-               else
-                       info->pcm_type = HDA_PCM_TYPE_SPDIF;
-               if (spec->multiout.dig_out_nid &&
-                   spec->stream_digital_playback) {
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
-               }
-               if (spec->dig_in_nid &&
-                   spec->stream_digital_capture) {
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
-               }
-               /* FIXME: do we need this for all Realtek codec models? */
-               codec->spdif_status_reset = 1;
-       }
-
-       if (spec->no_analog)
-               return 0;
-
-       /* If the use of more than one ADC is requested for the current
-        * model, configure a second analog capture-only PCM.
-        */
-       /* Additional Analaog capture for index #2 */
-       if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
-           (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
-               codec->num_pcms = 3;
-               info = spec->pcm_rec + 2;
-               info->name = spec->stream_name_analog;
-               if (spec->alt_dac_nid) {
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-                               *spec->stream_analog_alt_playback;
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
-                               spec->alt_dac_nid;
-               } else {
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-                               alc_pcm_null_stream;
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
-               }
-               if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) {
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-                               *spec->stream_analog_alt_capture;
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
-                               spec->adc_nids[1];
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
-                               spec->num_adc_nids - 1;
-               } else {
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-                               alc_pcm_null_stream;
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
-               }
-       }
-
-       return 0;
-}
-
-static inline void alc_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec && spec->shutup)
-               spec->shutup(codec);
-       snd_hda_shutup_pins(codec);
-}
-
-static void alc_free_kctls(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec->kctls.list) {
-               struct snd_kcontrol_new *kctl = spec->kctls.list;
-               int i;
-               for (i = 0; i < spec->kctls.used; i++)
-                       kfree(kctl[i].name);
-       }
-       snd_array_free(&spec->kctls);
-}
-
-static void alc_free(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (!spec)
-               return;
-
-       alc_shutup(codec);
-       snd_hda_input_jack_free(codec);
-       alc_free_kctls(codec);
-       kfree(spec);
-       snd_hda_detach_beep_device(codec);
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static void alc_power_eapd(struct hda_codec *codec)
-{
-       alc_auto_setup_eapd(codec, false);
-}
-
-static int alc_suspend(struct hda_codec *codec, pm_message_t state)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_shutup(codec);
-       if (spec && spec->power_hook)
-               spec->power_hook(codec);
-       return 0;
-}
-#endif
-
-#ifdef SND_HDA_NEEDS_RESUME
-static int alc_resume(struct hda_codec *codec)
-{
-       msleep(150); /* to avoid pop noise */
-       codec->patch_ops.init(codec);
-       snd_hda_codec_resume_amp(codec);
-       snd_hda_codec_resume_cache(codec);
-       hda_call_check_power_status(codec, 0x01);
-       return 0;
-}
-#endif
-
-/*
- */
-static const struct hda_codec_ops alc_patch_ops = {
-       .build_controls = alc_build_controls,
-       .build_pcms = alc_build_pcms,
-       .init = alc_init,
-       .free = alc_free,
-       .unsol_event = alc_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
-       .resume = alc_resume,
-#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       .suspend = alc_suspend,
-       .check_power_status = alc_check_power_status,
-#endif
-       .reboot_notify = alc_shutup,
-};
-
-/* replace the codec chip_name with the given string */
-static int alc_codec_rename(struct hda_codec *codec, const char *name)
-{
-       kfree(codec->chip_name);
-       codec->chip_name = kstrdup(name, GFP_KERNEL);
-       if (!codec->chip_name) {
-               alc_free(codec);
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-/*
- * Test configuration for debugging
- *
- * Almost all inputs/outputs are enabled.  I/O pins can be configured via
- * enum controls.
- */
-#ifdef CONFIG_SND_DEBUG
-static const hda_nid_t alc880_test_dac_nids[4] = {
-       0x02, 0x03, 0x04, 0x05
-};
-
-static const struct hda_input_mux alc880_test_capture_source = {
-       .num_items = 7,
-       .items = {
-               { "In-1", 0x0 },
-               { "In-2", 0x1 },
-               { "In-3", 0x2 },
-               { "In-4", 0x3 },
-               { "CD", 0x4 },
-               { "Front", 0x5 },
-               { "Surround", 0x6 },
-       },
-};
-
-static const struct hda_channel_mode alc880_test_modes[4] = {
-       { 2, NULL },
-       { 4, NULL },
-       { 6, NULL },
-       { 8, NULL },
-};
-
-static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       static const char * const texts[] = {
-               "N/A", "Line Out", "HP Out",
-               "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
-       };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 8;
-       if (uinfo->value.enumerated.item >= 8)
-               uinfo->value.enumerated.item = 7;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-       unsigned int pin_ctl, item = 0;
-
-       pin_ctl = snd_hda_codec_read(codec, nid, 0,
-                                    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-       if (pin_ctl & AC_PINCTL_OUT_EN) {
-               if (pin_ctl & AC_PINCTL_HP_EN)
-                       item = 2;
-               else
-                       item = 1;
-       } else if (pin_ctl & AC_PINCTL_IN_EN) {
-               switch (pin_ctl & AC_PINCTL_VREFEN) {
-               case AC_PINCTL_VREF_HIZ: item = 3; break;
-               case AC_PINCTL_VREF_50:  item = 4; break;
-               case AC_PINCTL_VREF_GRD: item = 5; break;
-               case AC_PINCTL_VREF_80:  item = 6; break;
-               case AC_PINCTL_VREF_100: item = 7; break;
-               }
-       }
-       ucontrol->value.enumerated.item[0] = item;
-       return 0;
-}
-
-static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-       static const unsigned int ctls[] = {
-               0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
-               AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
-               AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
-               AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
-               AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
-               AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
-       };
-       unsigned int old_ctl, new_ctl;
-
-       old_ctl = snd_hda_codec_read(codec, nid, 0,
-                                    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-       new_ctl = ctls[ucontrol->value.enumerated.item[0]];
-       if (old_ctl != new_ctl) {
-               int val;
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                         new_ctl);
-               val = ucontrol->value.enumerated.item[0] >= 3 ?
-                       HDA_AMP_MUTE : 0;
-               snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, val);
-               return 1;
-       }
-       return 0;
-}
-
-static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       static const char * const texts[] = {
-               "Front", "Surround", "CLFE", "Side"
-       };
-       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;
-}
-
-static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-       unsigned int sel;
-
-       sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
-       ucontrol->value.enumerated.item[0] = sel & 3;
-       return 0;
-}
-
-static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-       unsigned int sel;
-
-       sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
-       if (ucontrol->value.enumerated.item[0] != sel) {
-               sel = ucontrol->value.enumerated.item[0] & 3;
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_CONNECT_SEL, sel);
-               return 1;
-       }
-       return 0;
-}
-
-#define PIN_CTL_TEST(xname,nid) {                      \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,    \
-                       .name = xname,                 \
-                       .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-                       .info = alc_test_pin_ctl_info, \
-                       .get = alc_test_pin_ctl_get,   \
-                       .put = alc_test_pin_ctl_put,   \
-                       .private_value = nid           \
-                       }
-
-#define PIN_SRC_TEST(xname,nid) {                      \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,    \
-                       .name = xname,                 \
-                       .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-                       .info = alc_test_pin_src_info, \
-                       .get = alc_test_pin_src_get,   \
-                       .put = alc_test_pin_src_put,   \
-                       .private_value = nid           \
-                       }
-
-static const struct snd_kcontrol_new alc880_test_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       PIN_CTL_TEST("Front Pin Mode", 0x14),
-       PIN_CTL_TEST("Surround Pin Mode", 0x15),
-       PIN_CTL_TEST("CLFE Pin Mode", 0x16),
-       PIN_CTL_TEST("Side Pin Mode", 0x17),
-       PIN_CTL_TEST("In-1 Pin Mode", 0x18),
-       PIN_CTL_TEST("In-2 Pin Mode", 0x19),
-       PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
-       PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
-       PIN_SRC_TEST("In-1 Pin Source", 0x18),
-       PIN_SRC_TEST("In-2 Pin Source", 0x19),
-       PIN_SRC_TEST("In-3 Pin Source", 0x1a),
-       PIN_SRC_TEST("In-4 Pin Source", 0x1b),
-       HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
-       HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb alc880_test_init_verbs[] = {
-       /* Unmute inputs of 0x0c - 0x0f */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Vol output for 0x0c-0x0f */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Set output pins 0x14-0x17 */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Unmute output pins 0x14-0x17 */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Set input pins 0x18-0x1c */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* Mute input pins 0x18-0x1b */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* ADC set up */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Analog input/passthru */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       { }
-};
-#endif
-
-/*
- */
-
-static const char * const alc880_models[ALC880_MODEL_LAST] = {
-       [ALC880_3ST]            = "3stack",
-       [ALC880_TCL_S700]       = "tcl",
-       [ALC880_3ST_DIG]        = "3stack-digout",
-       [ALC880_CLEVO]          = "clevo",
-       [ALC880_5ST]            = "5stack",
-       [ALC880_5ST_DIG]        = "5stack-digout",
-       [ALC880_W810]           = "w810",
-       [ALC880_Z71V]           = "z71v",
-       [ALC880_6ST]            = "6stack",
-       [ALC880_6ST_DIG]        = "6stack-digout",
-       [ALC880_ASUS]           = "asus",
-       [ALC880_ASUS_W1V]       = "asus-w1v",
-       [ALC880_ASUS_DIG]       = "asus-dig",
-       [ALC880_ASUS_DIG2]      = "asus-dig2",
-       [ALC880_UNIWILL_DIG]    = "uniwill",
-       [ALC880_UNIWILL_P53]    = "uniwill-p53",
-       [ALC880_FUJITSU]        = "fujitsu",
-       [ALC880_F1734]          = "F1734",
-       [ALC880_LG]             = "lg",
-       [ALC880_LG_LW]          = "lg-lw",
-       [ALC880_MEDION_RIM]     = "medion",
-#ifdef CONFIG_SND_DEBUG
-       [ALC880_TEST]           = "test",
-#endif
-       [ALC880_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk alc880_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
-       SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
-       SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
-       SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
-       SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
-       SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
-       SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
-       SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
-       SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
-       SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
-       /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
-       SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
-       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
-       SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
-       SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
-       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
-       SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
-       SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
-       SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
-       SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
-       SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
-       SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
-       SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
-       SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
-       SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
-       SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
-       SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
-       SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
-       SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
-       SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
-       SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
-       SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
-       SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
-       SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
-       SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
-       SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
-       SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
-       SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
-       SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
-       SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
-       SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
-       SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
-       /* default Intel */
-       SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
-       SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
-       {}
-};
-
-/*
- * ALC880 codec presets
- */
-static const struct alc_config_preset alc880_presets[] = {
-       [ALC880_3ST] = {
-               .mixers = { alc880_three_stack_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_3stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-               .channel_mode = alc880_threestack_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_3ST_DIG] = {
-               .mixers = { alc880_three_stack_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_3stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-               .channel_mode = alc880_threestack_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_TCL_S700] = {
-               .mixers = { alc880_tcl_s700_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_tcl_S700_init_verbs,
-                               alc880_gpio2_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
-               .num_adc_nids = 1, /* single ADC */
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-               .channel_mode = alc880_2_jack_modes,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_5ST] = {
-               .mixers = { alc880_three_stack_mixer,
-                           alc880_five_stack_mixer},
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_5stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
-               .channel_mode = alc880_fivestack_modes,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_5ST_DIG] = {
-               .mixers = { alc880_three_stack_mixer,
-                           alc880_five_stack_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_5stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
-               .channel_mode = alc880_fivestack_modes,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_6ST] = {
-               .mixers = { alc880_six_stack_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_6stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
-               .dac_nids = alc880_6st_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
-               .channel_mode = alc880_sixstack_modes,
-               .input_mux = &alc880_6stack_capture_source,
-       },
-       [ALC880_6ST_DIG] = {
-               .mixers = { alc880_six_stack_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_6stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
-               .dac_nids = alc880_6st_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
-               .channel_mode = alc880_sixstack_modes,
-               .input_mux = &alc880_6stack_capture_source,
-       },
-       [ALC880_W810] = {
-               .mixers = { alc880_w810_base_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_w810_init_verbs,
-                               alc880_gpio2_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
-               .dac_nids = alc880_w810_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
-               .channel_mode = alc880_w810_modes,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_Z71V] = {
-               .mixers = { alc880_z71v_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_z71v_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
-               .dac_nids = alc880_z71v_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-               .channel_mode = alc880_2_jack_modes,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_F1734] = {
-               .mixers = { alc880_f1734_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_f1734_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
-               .dac_nids = alc880_f1734_dac_nids,
-               .hp_nid = 0x02,
-               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-               .channel_mode = alc880_2_jack_modes,
-               .input_mux = &alc880_f1734_capture_source,
-               .unsol_event = alc880_uniwill_p53_unsol_event,
-               .setup = alc880_uniwill_p53_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC880_ASUS] = {
-               .mixers = { alc880_asus_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_asus_init_verbs,
-                               alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-               .dac_nids = alc880_asus_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-               .channel_mode = alc880_asus_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_ASUS_DIG] = {
-               .mixers = { alc880_asus_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_asus_init_verbs,
-                               alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-               .dac_nids = alc880_asus_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-               .channel_mode = alc880_asus_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_ASUS_DIG2] = {
-               .mixers = { alc880_asus_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_asus_init_verbs,
-                               alc880_gpio2_init_verbs }, /* use GPIO2 */
-               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-               .dac_nids = alc880_asus_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-               .channel_mode = alc880_asus_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_ASUS_W1V] = {
-               .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_asus_init_verbs,
-                               alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-               .dac_nids = alc880_asus_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-               .channel_mode = alc880_asus_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_UNIWILL_DIG] = {
-               .mixers = { alc880_asus_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_asus_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-               .dac_nids = alc880_asus_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-               .channel_mode = alc880_asus_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_UNIWILL] = {
-               .mixers = { alc880_uniwill_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_uniwill_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-               .dac_nids = alc880_asus_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-               .channel_mode = alc880_threestack_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_capture_source,
-               .unsol_event = alc880_uniwill_unsol_event,
-               .setup = alc880_uniwill_setup,
-               .init_hook = alc880_uniwill_init_hook,
-       },
-       [ALC880_UNIWILL_P53] = {
-               .mixers = { alc880_uniwill_p53_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_uniwill_p53_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-               .dac_nids = alc880_asus_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
-               .channel_mode = alc880_threestack_modes,
-               .input_mux = &alc880_capture_source,
-               .unsol_event = alc880_uniwill_p53_unsol_event,
-               .setup = alc880_uniwill_p53_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC880_FUJITSU] = {
-               .mixers = { alc880_fujitsu_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_uniwill_p53_init_verbs,
-                               alc880_beep_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-               .channel_mode = alc880_2_jack_modes,
-               .input_mux = &alc880_capture_source,
-               .unsol_event = alc880_uniwill_p53_unsol_event,
-               .setup = alc880_uniwill_p53_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC880_CLEVO] = {
-               .mixers = { alc880_three_stack_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_pin_clevo_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-               .channel_mode = alc880_threestack_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_capture_source,
-       },
-       [ALC880_LG] = {
-               .mixers = { alc880_lg_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_lg_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
-               .dac_nids = alc880_lg_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
-               .channel_mode = alc880_lg_ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc880_lg_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc880_lg_setup,
-               .init_hook = alc_hp_automute,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-               .loopbacks = alc880_lg_loopbacks,
-#endif
-       },
-       [ALC880_LG_LW] = {
-               .mixers = { alc880_lg_lw_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_lg_lw_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
-               .channel_mode = alc880_lg_lw_modes,
-               .input_mux = &alc880_lg_lw_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc880_lg_lw_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC880_MEDION_RIM] = {
-               .mixers = { alc880_medion_rim_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_medion_rim_init_verbs,
-                               alc_gpio2_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-               .channel_mode = alc880_2_jack_modes,
-               .input_mux = &alc880_medion_rim_capture_source,
-               .unsol_event = alc880_medion_rim_unsol_event,
-               .setup = alc880_medion_rim_setup,
-               .init_hook = alc880_medion_rim_automute,
-       },
-#ifdef CONFIG_SND_DEBUG
-       [ALC880_TEST] = {
-               .mixers = { alc880_test_mixer },
-               .init_verbs = { alc880_test_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
-               .dac_nids = alc880_test_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
-               .channel_mode = alc880_test_modes,
-               .input_mux = &alc880_test_capture_source,
-       },
-#endif
-};
-
-/*
- * Automatic parse of I/O pins from the BIOS configuration
- */
-
-enum {
-       ALC_CTL_WIDGET_VOL,
-       ALC_CTL_WIDGET_MUTE,
-       ALC_CTL_BIND_MUTE,
-};
-static const struct snd_kcontrol_new alc880_control_templates[] = {
-       HDA_CODEC_VOLUME(NULL, 0, 0, 0),
-       HDA_CODEC_MUTE(NULL, 0, 0, 0),
-       HDA_BIND_MUTE(NULL, 0, 0, 0),
-};
-
-static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
-{
-       snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
-       return snd_array_new(&spec->kctls);
-}
-
-/* add dynamic controls */
-static int add_control(struct alc_spec *spec, int type, const char *name,
-                      int cidx, unsigned long val)
-{
-       struct snd_kcontrol_new *knew;
-
-       knew = alc_kcontrol_new(spec);
-       if (!knew)
-               return -ENOMEM;
-       *knew = alc880_control_templates[type];
-       knew->name = kstrdup(name, GFP_KERNEL);
-       if (!knew->name)
-               return -ENOMEM;
-       knew->index = cidx;
-       if (get_amp_nid_(val))
-               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
-       knew->private_value = val;
-       return 0;
-}
-
-static int add_control_with_pfx(struct alc_spec *spec, int type,
-                               const char *pfx, const char *dir,
-                               const char *sfx, int cidx, unsigned long val)
-{
-       char name[32];
-       snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
-       return add_control(spec, type, name, cidx, val);
-}
-
-#define add_pb_vol_ctrl(spec, type, pfx, val)                  \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
-#define add_pb_sw_ctrl(spec, type, pfx, val)                   \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
-#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)                  \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
-#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)                   \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
-
-#define alc880_is_fixed_pin(nid)       ((nid) >= 0x14 && (nid) <= 0x17)
-#define alc880_fixed_pin_idx(nid)      ((nid) - 0x14)
-#define alc880_is_multi_pin(nid)       ((nid) >= 0x18)
-#define alc880_multi_pin_idx(nid)      ((nid) - 0x18)
-#define alc880_idx_to_dac(nid)         ((nid) + 0x02)
-#define alc880_dac_to_idx(nid)         ((nid) - 0x02)
-#define alc880_idx_to_mixer(nid)       ((nid) + 0x0c)
-#define alc880_idx_to_selector(nid)    ((nid) + 0x10)
-#define ALC880_PIN_CD_NID              0x1c
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
-                                    const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid;
-       int assigned[4];
-       int i, j;
-
-       memset(assigned, 0, sizeof(assigned));
-       spec->multiout.dac_nids = spec->private_dac_nids;
-
-       /* check the pins hardwired to audio widget */
-       for (i = 0; i < cfg->line_outs; i++) {
-               nid = cfg->line_out_pins[i];
-               if (alc880_is_fixed_pin(nid)) {
-                       int idx = alc880_fixed_pin_idx(nid);
-                       spec->private_dac_nids[i] = alc880_idx_to_dac(idx);
-                       assigned[idx] = 1;
-               }
-       }
-       /* left pins can be connect to any audio widget */
-       for (i = 0; i < cfg->line_outs; i++) {
-               nid = cfg->line_out_pins[i];
-               if (alc880_is_fixed_pin(nid))
-                       continue;
-               /* search for an empty channel */
-               for (j = 0; j < cfg->line_outs; j++) {
-                       if (!assigned[j]) {
-                               spec->private_dac_nids[i] =
-                                       alc880_idx_to_dac(j);
-                               assigned[j] = 1;
-                               break;
-                       }
-               }
-       }
-       spec->multiout.num_dacs = cfg->line_outs;
-       return 0;
-}
-
-static const char *alc_get_line_out_pfx(struct alc_spec *spec,
-                                       bool can_be_master)
-{
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-
-       if (cfg->line_outs == 1 && !spec->multi_ios &&
-           !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
-               return "Master";
-
-       switch (cfg->line_out_type) {
-       case AUTO_PIN_SPEAKER_OUT:
-               if (cfg->line_outs == 1)
-                       return "Speaker";
-               break;
-       case AUTO_PIN_HP_OUT:
-               return "Headphone";
-       default:
-               if (cfg->line_outs == 1 && !spec->multi_ios)
-                       return "PCM";
-               break;
-       }
-       return NULL;
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       static const char * const chname[4] = {
-               "Front", "Surround", NULL /*CLFE*/, "Side"
-       };
-       const char *pfx = alc_get_line_out_pfx(spec, false);
-       hda_nid_t nid;
-       int i, err, noutputs;
-
-       noutputs = cfg->line_outs;
-       if (spec->multi_ios > 0)
-               noutputs += spec->multi_ios;
-
-       for (i = 0; i < noutputs; i++) {
-               if (!spec->multiout.dac_nids[i])
-                       continue;
-               nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
-               if (!pfx && i == 2) {
-                       /* Center/LFE */
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                             "Center",
-                                         HDA_COMPOSE_AMP_VAL(nid, 1, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                             "LFE",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                            "Center",
-                                         HDA_COMPOSE_AMP_VAL(nid, 1, 2,
-                                                             HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                            "LFE",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 2,
-                                                             HDA_INPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       const char *name = pfx;
-                       int index = i;
-                       if (!name) {
-                               name = chname[i];
-                               index = 0;
-                       }
-                       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                               name, index,
-                                         HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                              name, index,
-                                         HDA_COMPOSE_AMP_VAL(nid, 3, 2,
-                                                             HDA_INPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-/* add playback controls for speaker and HP outputs */
-static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
-                                       const char *pfx)
-{
-       hda_nid_t nid;
-       int err;
-
-       if (!pin)
-               return 0;
-
-       if (alc880_is_fixed_pin(pin)) {
-               nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
-               /* specify the DAC as the extra output */
-               if (!spec->multiout.hp_nid)
-                       spec->multiout.hp_nid = nid;
-               else
-                       spec->multiout.extra_out_nid[0] = nid;
-               /* control HP volume/switch on the output mixer amp */
-               nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
-               if (err < 0)
-                       return err;
-       } else if (alc880_is_multi_pin(pin)) {
-               /* set manual connection */
-               /* we have only a switch on HP-out PIN */
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
-                                 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-/* create input playback/capture controls for the given pin */
-static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
-                           const char *ctlname, int ctlidx,
-                           int idx, hda_nid_t mix_nid)
-{
-       int err;
-
-       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
-                         HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
-       if (err < 0)
-               return err;
-       err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
-                         HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
-       if (err < 0)
-               return err;
-       return 0;
-}
-
-static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
-{
-       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
-       return (pincap & AC_PINCAP_IN) != 0;
-}
-
-/* create playback/capture controls for input pins */
-static int alc_auto_create_input_ctls(struct hda_codec *codec,
-                                     const struct auto_pin_cfg *cfg,
-                                     hda_nid_t mixer,
-                                     hda_nid_t cap1, hda_nid_t cap2)
-{
-       struct alc_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx, type_idx = 0;
-       const char *prev_label = NULL;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t pin;
-               const char *label;
-
-               pin = cfg->inputs[i].pin;
-               if (!alc_is_input_pin(codec, pin))
-                       continue;
-
-               label = hda_get_autocfg_input_label(codec, cfg, i);
-               if (prev_label && !strcmp(label, prev_label))
-                       type_idx++;
-               else
-                       type_idx = 0;
-               prev_label = label;
-
-               if (mixer) {
-                       idx = get_connection_index(codec, mixer, pin);
-                       if (idx >= 0) {
-                               err = new_analog_input(spec, pin,
-                                                      label, type_idx,
-                                                      idx, mixer);
-                               if (err < 0)
-                                       return err;
-                       }
-               }
-
-               if (!cap1)
-                       continue;
-               idx = get_connection_index(codec, cap1, pin);
-               if (idx < 0 && cap2)
-                       idx = get_connection_index(codec, cap2, pin);
-               if (idx >= 0)
-                       snd_hda_add_imux_item(imux, label, idx, NULL);
-       }
-       return 0;
-}
-
-static int alc880_auto_create_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
-}
-
-static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned int pin_type)
-{
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pin_type);
-       /* unmute pin */
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_UNMUTE);
-}
-
-static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type,
-                                             int dac_idx)
-{
-       alc_set_pin_output(codec, nid, pin_type);
-       /* need the manual connection? */
-       if (alc880_is_multi_pin(nid)) {
-               struct alc_spec *spec = codec->spec;
-               int idx = alc880_multi_pin_idx(nid);
-               snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
-                                   AC_VERB_SET_CONNECT_SEL,
-                                   alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
-       }
-}
-
-static int get_pin_type(int line_out_type)
-{
-       if (line_out_type == AUTO_PIN_HP_OUT)
-               return PIN_HP;
-       else
-               return PIN_OUT;
-}
-
-static void alc880_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->autocfg.line_outs; i++) {
-               hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
-       }
-}
-
-static void alc880_auto_init_extra_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t pin;
-
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin) /* connect to front */
-               alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
-       pin = spec->autocfg.hp_pins[0];
-       if (pin) /* connect to front */
-               alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
-}
-
-static void alc880_auto_init_analog_input(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               if (alc_is_input_pin(codec, nid)) {
-                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
-                       if (nid != ALC880_PIN_CD_NID &&
-                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
-                               snd_hda_codec_write(codec, nid, 0,
-                                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                                   AMP_OUT_MUTE);
-               }
-       }
-}
-
-static void alc880_auto_init_input_src(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int c;
-
-       for (c = 0; c < spec->num_adc_nids; c++) {
-               unsigned int mux_idx;
-               const struct hda_input_mux *imux;
-               mux_idx = c >= spec->num_mux_defs ? 0 : c;
-               imux = &spec->input_mux[mux_idx];
-               if (!imux->num_items && mux_idx > 0)
-                       imux = &spec->input_mux[0];
-               if (imux)
-                       snd_hda_codec_write(codec, spec->adc_nids[c], 0,
-                                           AC_VERB_SET_CONNECT_SEL,
-                                           imux->items[0].index);
-       }
-}
-
-static int alc_auto_add_multi_channel_mode(struct hda_codec *codec);
-
-/* parse the BIOS configuration and set up the alc_spec */
-/* return 1 if successful, 0 if the proper config is not found,
- * or a negative error code
- */
-static int alc880_parse_auto_config(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc880_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs)
-               return 0; /* can't find valid BIOS pin config */
-
-       err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_add_multi_channel_mode(codec);
-       if (err < 0)
-               return err;
-       err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc880_auto_create_extra_out(spec,
-                                          spec->autocfg.speaker_pins[0],
-                                          "Speaker");
-       if (err < 0)
-               return err;
-       err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
-                                          "Headphone");
-       if (err < 0)
-               return err;
-       err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       add_verb(spec, alc880_volume_init_verbs);
-
-       spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux[0];
-
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
-       return 1;
-}
-
-/* additional initialization for auto-configuration model */
-static void alc880_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc880_auto_init_multi_out(codec);
-       alc880_auto_init_extra_out(codec);
-       alc880_auto_init_analog_input(codec);
-       alc880_auto_init_input_src(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
-}
-
-/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
- * one of two digital mic pins, e.g. on ALC272
- */
-static void fixup_automic_adc(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_adc_nids; i++) {
-               hda_nid_t cap = spec->capsrc_nids ?
-                       spec->capsrc_nids[i] : spec->adc_nids[i];
-               int iidx, eidx;
-
-               iidx = get_connection_index(codec, cap, spec->int_mic.pin);
-               if (iidx < 0)
-                       continue;
-               eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
-               if (eidx < 0)
-                       continue;
-               spec->int_mic.mux_idx = iidx;
-               spec->ext_mic.mux_idx = eidx;
-               if (spec->capsrc_nids)
-                       spec->capsrc_nids += i;
-               spec->adc_nids += i;
-               spec->num_adc_nids = 1;
-               /* optional dock-mic */
-               eidx = get_connection_index(codec, cap, spec->dock_mic.pin);
-               if (eidx < 0)
-                       spec->dock_mic.pin = 0;
-               else
-                       spec->dock_mic.mux_idx = eidx;
-               return;
-       }
-       snd_printd(KERN_INFO "hda_codec: %s: "
-                  "No ADC/MUX containing both 0x%x and 0x%x pins\n",
-                  codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
-       spec->auto_mic = 0; /* disable auto-mic to be sure */
-}
-
-/* select or unmute the given capsrc route */
-static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
-                                   int idx)
-{
-       if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
-               snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
-                                        HDA_AMP_MUTE, 0);
-       } else {
-               snd_hda_codec_write_cache(codec, cap, 0,
-                                         AC_VERB_SET_CONNECT_SEL, idx);
-       }
-}
-
-/* set the default connection to that pin */
-static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       if (!pin)
-               return 0;
-       for (i = 0; i < spec->num_adc_nids; i++) {
-               hda_nid_t cap = spec->capsrc_nids ?
-                       spec->capsrc_nids[i] : spec->adc_nids[i];
-               int idx;
-
-               idx = get_connection_index(codec, cap, pin);
-               if (idx < 0)
-                       continue;
-               select_or_unmute_capsrc(codec, cap, idx);
-               return i; /* return the found index */
-       }
-       return -1; /* not found */
-}
-
-/* choose the ADC/MUX containing the input pin and initialize the setup */
-static void fixup_single_adc(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-
-       /* search for the input pin; there must be only one */
-       if (cfg->num_inputs != 1)
-               return;
-       i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
-       if (i >= 0) {
-               /* use only this ADC */
-               if (spec->capsrc_nids)
-                       spec->capsrc_nids += i;
-               spec->adc_nids += i;
-               spec->num_adc_nids = 1;
-               spec->single_input_src = 1;
-       }
-}
-
-/* initialize dual adcs */
-static void fixup_dual_adc_switch(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       init_capsrc_for_pin(codec, spec->ext_mic.pin);
-       init_capsrc_for_pin(codec, spec->dock_mic.pin);
-       init_capsrc_for_pin(codec, spec->int_mic.pin);
-}
-
-/* initialize some special cases for input sources */
-static void alc_init_special_input_src(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       if (spec->dual_adc_switch)
-               fixup_dual_adc_switch(codec);
-       else if (spec->single_input_src)
-               init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin);
-}
-
-static void set_capture_mixer(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       static const struct snd_kcontrol_new *caps[2][3] = {
-               { alc_capture_mixer_nosrc1,
-                 alc_capture_mixer_nosrc2,
-                 alc_capture_mixer_nosrc3 },
-               { alc_capture_mixer1,
-                 alc_capture_mixer2,
-                 alc_capture_mixer3 },
-       };
-       if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
-               int mux = 0;
-               int num_adcs = spec->num_adc_nids;
-               if (spec->dual_adc_switch)
-                       num_adcs = 1;
-               else if (spec->auto_mic)
-                       fixup_automic_adc(codec);
-               else if (spec->input_mux) {
-                       if (spec->input_mux->num_items > 1)
-                               mux = 1;
-                       else if (spec->input_mux->num_items == 1)
-                               fixup_single_adc(codec);
-               }
-               spec->cap_mixer = caps[mux][num_adcs - 1];
-       }
-}
-
-/* fill adc_nids (and capsrc_nids) containing all active input pins */
-static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids,
-                                int num_nids)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int n;
-       hda_nid_t fallback_adc = 0, fallback_cap = 0;
-
-       for (n = 0; n < num_nids; n++) {
-               hda_nid_t adc, cap;
-               hda_nid_t conn[HDA_MAX_NUM_INPUTS];
-               int nconns, i, j;
-
-               adc = nids[n];
-               if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
-                       continue;
-               cap = adc;
-               nconns = snd_hda_get_connections(codec, cap, conn,
-                                                ARRAY_SIZE(conn));
-               if (nconns == 1) {
-                       cap = conn[0];
-                       nconns = snd_hda_get_connections(codec, cap, conn,
-                                                        ARRAY_SIZE(conn));
-               }
-               if (nconns <= 0)
-                       continue;
-               if (!fallback_adc) {
-                       fallback_adc = adc;
-                       fallback_cap = cap;
-               }
-               for (i = 0; i < cfg->num_inputs; i++) {
-                       hda_nid_t nid = cfg->inputs[i].pin;
-                       for (j = 0; j < nconns; j++) {
-                               if (conn[j] == nid)
-                                       break;
-                       }
-                       if (j >= nconns)
-                               break;
-               }
-               if (i >= cfg->num_inputs) {
-                       int num_adcs = spec->num_adc_nids;
-                       spec->private_adc_nids[num_adcs] = adc;
-                       spec->private_capsrc_nids[num_adcs] = cap;
-                       spec->num_adc_nids++;
-                       spec->adc_nids = spec->private_adc_nids;
-                       if (adc != cap)
-                               spec->capsrc_nids = spec->private_capsrc_nids;
-               }
-       }
-       if (!spec->num_adc_nids) {
-               printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
-                      " using fallback 0x%x\n",
-                      codec->chip_name, fallback_adc);
-               spec->private_adc_nids[0] = fallback_adc;
-               spec->adc_nids = spec->private_adc_nids;
-               if (fallback_adc != fallback_cap) {
-                       spec->private_capsrc_nids[0] = fallback_cap;
-                       spec->capsrc_nids = spec->private_adc_nids;
-               }
-       }
-}
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-#define set_beep_amp(spec, nid, idx, dir) \
-       ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
-
-static const struct snd_pci_quirk beep_white_list[] = {
-       SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
-       SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
-       SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
-       SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
-       SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
-       {}
-};
-
-static inline int has_cdefine_beep(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       const struct snd_pci_quirk *q;
-       q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
-       if (q)
-               return q->value;
-       return spec->cdefine.enable_pcbeep;
-}
-#else
-#define set_beep_amp(spec, nid, idx, dir) /* NOP */
-#define has_cdefine_beep(codec)                0
-#endif
-
-/*
- * OK, here we have finally the patch for ALC880
- */
-
-static int patch_alc880(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int board_config;
-       int err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
-                                                 alc880_models,
-                                                 alc880_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = ALC880_AUTO;
-       }
-
-       if (board_config == ALC880_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc880_parse_auto_config(codec);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               } else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using 3-stack mode...\n");
-                       board_config = ALC880_3ST;
-               }
-       }
-
-       err = snd_hda_attach_beep_device(codec, 0x1);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
-       }
-
-       if (board_config != ALC880_AUTO)
-               setup_preset(codec, &alc880_presets[board_config]);
-
-       spec->stream_analog_playback = &alc880_pcm_analog_playback;
-       spec->stream_analog_capture = &alc880_pcm_analog_capture;
-       spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
-
-       spec->stream_digital_playback = &alc880_pcm_digital_playback;
-       spec->stream_digital_capture = &alc880_pcm_digital_capture;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               /* check whether NID 0x07 is valid */
-               unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
-               /* get type */
-               wcap = get_wcaps_type(wcap);
-               if (wcap != AC_WID_AUD_IN) {
-                       spec->adc_nids = alc880_adc_nids_alt;
-                       spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
-               } else {
-                       spec->adc_nids = alc880_adc_nids;
-                       spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
-               }
-       }
-       set_capture_mixer(codec);
-       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-
-       spec->vmaster_nid = 0x0c;
-
-       codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC880_AUTO)
-               spec->init_hook = alc880_auto_init;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc880_loopbacks;
-#endif
-
-       return 0;
-}
-
-
-/*
- * ALC260 support
- */
-
-static const hda_nid_t alc260_dac_nids[1] = {
-       /* front */
-       0x02,
-};
-
-static const hda_nid_t alc260_adc_nids[1] = {
-       /* ADC0 */
-       0x04,
-};
-
-static const hda_nid_t alc260_adc_nids_alt[1] = {
-       /* ADC1 */
-       0x05,
-};
-
-/* NIDs used when simultaneous access to both ADCs makes sense.  Note that
- * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
- */
-static const hda_nid_t alc260_dual_adc_nids[2] = {
-       /* ADC0, ADC1 */
-       0x04, 0x05
-};
-
-#define ALC260_DIGOUT_NID      0x03
-#define ALC260_DIGIN_NID       0x06
-
-static const struct hda_input_mux alc260_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
- * headphone jack and the internal CD lines since these are the only pins at
- * which audio can appear.  For flexibility, also allow the option of
- * recording the mixer output on the second ADC (ADC0 doesn't have a
- * connection to the mixer output).
- */
-static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
-       {
-               .num_items = 3,
-               .items = {
-                       { "Mic/Line", 0x0 },
-                       { "CD", 0x4 },
-                       { "Headphone", 0x2 },
-               },
-       },
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic/Line", 0x0 },
-                       { "CD", 0x4 },
-                       { "Headphone", 0x2 },
-                       { "Mixer", 0x5 },
-               },
-       },
-
-};
-
-/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
- * the Fujitsu S702x, but jacks are marked differently.
- */
-static const struct hda_input_mux alc260_acer_capture_sources[2] = {
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Headphone", 0x5 },
-               },
-       },
-       {
-               .num_items = 5,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Headphone", 0x6 },
-                       { "Mixer", 0x5 },
-               },
-       },
-};
-
-/* Maxdata Favorit 100XS */
-static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
-       {
-               .num_items = 2,
-               .items = {
-                       { "Line/Mic", 0x0 },
-                       { "CD", 0x4 },
-               },
-       },
-       {
-               .num_items = 3,
-               .items = {
-                       { "Line/Mic", 0x0 },
-                       { "CD", 0x4 },
-                       { "Mixer", 0x5 },
-               },
-       },
-};
-
-/*
- * This is just place-holder, so there's something for alc_build_pcms to look
- * at when it calculates the maximum number of channels. ALC260 has no mixer
- * element which allows changing the channel mode, so the verb list is
- * never used.
- */
-static const struct hda_channel_mode alc260_modes[1] = {
-       { 2, NULL },
-};
-
-
-/* Mixer combinations
- *
- * basic: base_output + input + pc_beep + capture
- * HP: base_output + input + capture_alt
- * HP_3013: hp_3013 + input + capture
- * fujitsu: fujitsu + capture
- * acer: acer + capture
- */
-
-static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc260_input_mixer[] = {
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
-       { } /* end */
-};
-
-/* update HP, line and mono out pins according to the master switch */
-static void alc260_hp_master_update(struct hda_codec *codec)
-{
-       update_speakers(codec);
-}
-
-static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       *ucontrol->value.integer.value = !spec->master_mute;
-       return 0;
-}
-
-static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       int val = !*ucontrol->value.integer.value;
-
-       if (val == spec->master_mute)
-               return 0;
-       spec->master_mute = val;
-       alc260_hp_master_update(codec);
-       return 1;
-}
-
-static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc260_hp_master_sw_get,
-               .put = alc260_hp_master_sw_put,
-       },
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
-                             HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc260_hp_unsol_verbs[] = {
-       {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {},
-};
-
-static void alc260_hp_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x0f;
-       spec->autocfg.speaker_pins[0] = 0x10;
-       spec->autocfg.speaker_pins[1] = 0x11;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc260_hp_master_sw_get,
-               .put = alc260_hp_master_sw_put,
-       },
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static void alc260_hp_3013_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x10;
-       spec->autocfg.speaker_pins[1] = 0x11;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
-static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
-static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
-       HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {},
-};
-
-static void alc260_hp_3012_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x10;
-       spec->autocfg.speaker_pins[0] = 0x0f;
-       spec->autocfg.speaker_pins[1] = 0x11;
-       spec->autocfg.speaker_pins[2] = 0x15;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-/* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12,
- * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
- */
-static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
-       ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
-       ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
-       { } /* end */
-};
-
-/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks.  Note that current
- * versions of the ALC260 don't act on requests to enable mic bias from NID
- * 0x0f (used to drive the headphone jack in these laptops).  The ALC260
- * datasheet doesn't mention this restriction.  At this stage it's not clear
- * whether this behaviour is intentional or is a hardware bug in chip
- * revisions available in early 2006.  Therefore for now allow the
- * "Headphone Jack Mode" control to span all choices, but if it turns out
- * that the lack of mic bias for this NID is intentional we could change the
- * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
- *
- * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
- * don't appear to make the mic bias available from the "line" jack, even
- * though the NID used for this jack (0x14) can supply it.  The theory is
- * that perhaps Acer have included blocking capacitors between the ALC260
- * and the output jack.  If this turns out to be the case for all such
- * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
- * to ALC_PIN_DIR_INOUT_NOMICBIAS.
- *
- * The C20x Tablet series have a mono internal speaker which is controlled
- * via the chip's Mono sum widget and pin complex, so include the necessary
- * controls for such models.  On models without a "mono speaker" the control
- * won't do anything.
- */
-static const struct snd_kcontrol_new alc260_acer_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
-       ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
-       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
-                             HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
-                          HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-       ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
-       ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-       { } /* end */
-};
-
-/* Maxdata Favorit 100XS: one output and one input (0x12) jack
- */
-static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
-       ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
-       HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-       ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
-       { } /* end */
-};
-
-/* Packard bell V7900  ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
- * Line In jack = 0x14, CD audio =  0x16, pc beep = 0x17.
- */
-static const struct snd_kcontrol_new alc260_will_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-       ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
-       ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-       { } /* end */
-};
-
-/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
- * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
- */
-static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-       ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
-       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
-       ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-       { } /* end */
-};
-
-/*
- * initialization verbs
- */
-static const struct hda_verb alc260_init_verbs[] = {
-       /* Line In pin widget for input */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* CD pin widget for input */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* Mic1 (rear panel) pin widget for input and vref at 80% */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       /* Mic2 (front panel) pin widget for input and vref at 80% */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       /* LINE-2 is used for line-out in rear */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* select line-out */
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* LINE-OUT pin */
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* enable HP */
-       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* enable Mono */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* mute capture amp left and right */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* set connection select to line in (default select for this ADC) */
-       {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* mute capture amp left and right */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* set connection select to line in (default select for this ADC) */
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* set vol=0 Line-Out mixer amp left and right */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* unmute pin widget amp left and right (no gain on this amp) */
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* set vol=0 HP mixer amp left and right */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* unmute pin widget amp left and right (no gain on this amp) */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* set vol=0 Mono mixer amp left and right */
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* unmute pin widget amp left and right (no gain on this amp) */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* unmute LINE-2 out pin */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
-        * Line In 2 = 0x03
-        */
-       /* mute analog inputs */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
-       /* mute Front out path */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* mute Headphone out path */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* mute Mono out path */
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       { }
-};
-
-#if 0 /* should be identical with alc260_init_verbs? */
-static const struct hda_verb alc260_hp_init_verbs[] = {
-       /* Headphone and output */
-       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
-       /* mono output */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       /* Mic1 (rear panel) pin widget for input and vref at 80% */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       /* Mic2 (front panel) pin widget for input and vref at 80% */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       /* Line In pin widget for input */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       /* Line-2 pin widget for output */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       /* CD pin widget for input */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       /* unmute amp left and right */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
-       /* set connection select to line in (default select for this ADC) */
-       {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* unmute Line-Out mixer amp left and right (volume = 0) */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       /* mute pin widget amp left and right (no gain on this amp) */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       /* unmute HP mixer amp left and right (volume = 0) */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       /* mute pin widget amp left and right (no gain on this amp) */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
-        * Line In 2 = 0x03
-        */
-       /* mute analog inputs */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
-       /* Unmute Front out path */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       /* Unmute Headphone out path */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       /* Unmute Mono out path */
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       { }
-};
-#endif
-
-static const struct hda_verb alc260_hp_3013_init_verbs[] = {
-       /* Line out and output */
-       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       /* mono output */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       /* Mic1 (rear panel) pin widget for input and vref at 80% */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       /* Mic2 (front panel) pin widget for input and vref at 80% */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       /* Line In pin widget for input */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       /* Headphone pin widget for output */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
-       /* CD pin widget for input */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       /* unmute amp left and right */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
-       /* set connection select to line in (default select for this ADC) */
-       {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* unmute Line-Out mixer amp left and right (volume = 0) */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       /* mute pin widget amp left and right (no gain on this amp) */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       /* unmute HP mixer amp left and right (volume = 0) */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       /* mute pin widget amp left and right (no gain on this amp) */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
-        * Line In 2 = 0x03
-        */
-       /* mute analog inputs */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
-       /* Unmute Front out path */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       /* Unmute Headphone out path */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       /* Unmute Mono out path */
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       { }
-};
-
-/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
- * laptops.  ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
- * audio = 0x16, internal speaker = 0x10.
- */
-static const struct hda_verb alc260_fujitsu_init_verbs[] = {
-       /* Disable all GPIOs */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0},
-       /* Internal speaker is connected to headphone pin */
-       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Headphone/Line-out jack connects to Line1 pin; make it an output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* Ensure all other unused pins are disabled and muted. */
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-
-       /* Disable digital (SPDIF) pins */
-       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
-       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
-       /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
-        * when acting as an output.
-        */
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* Start with output sum widgets muted and their output gains at min */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Unmute Line1 pin widget output buffer since it starts as an output.
-        * If the pin mode is changed by the user the pin mode control will
-        * take care of enabling the pin's input/output buffers as needed.
-        * Therefore there's no need to enable the input buffer at this
-        * stage.
-        */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Unmute input buffer of pin widget used for Line-in (no equiv
-        * mixer ctrl)
-        */
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Mute capture amp left and right */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       /* Set ADC connection select to match default mixer setting - line
-        * in (on mic1 pin)
-        */
-       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Do the same for the second ADC: mute capture input amp and
-        * set ADC connection to line in (on mic1 pin)
-        */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Mute all inputs to mixer widget (even unconnected ones) */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
-
-       { }
-};
-
-/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
- * similar laptops (adapted from Fujitsu init verbs).
- */
-static const struct hda_verb alc260_acer_init_verbs[] = {
-       /* On TravelMate laptops, GPIO 0 enables the internal speaker and
-        * the headphone jack.  Turn this on and rely on the standard mute
-        * methods whenever the user wants to turn these outputs off.
-        */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
-       /* Internal speaker/Headphone jack is connected to Line-out pin */
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Internal microphone/Mic jack is connected to Mic1 pin */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-       /* Line In jack is connected to Line1 pin */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Ensure all other unused pins are disabled and muted. */
-       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       /* Disable digital (SPDIF) pins */
-       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
-       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
-       /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
-        * bus when acting as outputs.
-        */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* Start with output sum widgets muted and their output gains at min */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* Unmute Line-out pin widget amp left and right
-        * (no equiv mixer ctrl)
-        */
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Unmute Mic1 and Line1 pin widget input buffers since they start as
-        * inputs. If the pin mode is changed by the user the pin mode control
-        * will take care of enabling the pin's input/output buffers as needed.
-        * Therefore there's no need to enable the input buffer at this
-        * stage.
-        */
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Mute capture amp left and right */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       /* Set ADC connection select to match default mixer setting - mic
-        * (on mic1 pin)
-        */
-       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Do similar with the second ADC: mute capture input amp and
-        * set ADC connection to mic to match ALSA's default state.
-        */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Mute all inputs to mixer widget (even unconnected ones) */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
-
-       { }
-};
-
-/* Initialisation sequence for Maxdata Favorit 100XS
- * (adapted from Acer init verbs).
- */
-static const struct hda_verb alc260_favorit100_init_verbs[] = {
-       /* GPIO 0 enables the output jack.
-        * Turn this on and rely on the standard mute
-        * methods whenever the user wants to turn these outputs off.
-        */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
-       /* Line/Mic input jack is connected to Mic1 pin */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-       /* Ensure all other unused pins are disabled and muted. */
-       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       /* Disable digital (SPDIF) pins */
-       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
-       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
-       /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
-        * bus when acting as outputs.
-        */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* Start with output sum widgets muted and their output gains at min */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* Unmute Line-out pin widget amp left and right
-        * (no equiv mixer ctrl)
-        */
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Unmute Mic1 and Line1 pin widget input buffers since they start as
-        * inputs. If the pin mode is changed by the user the pin mode control
-        * will take care of enabling the pin's input/output buffers as needed.
-        * Therefore there's no need to enable the input buffer at this
-        * stage.
-        */
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Mute capture amp left and right */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       /* Set ADC connection select to match default mixer setting - mic
-        * (on mic1 pin)
-        */
-       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Do similar with the second ADC: mute capture input amp and
-        * set ADC connection to mic to match ALSA's default state.
-        */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Mute all inputs to mixer widget (even unconnected ones) */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
-
-       { }
-};
-
-static const struct hda_verb alc260_will_verbs[] = {
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-       {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
-       {}
-};
-
-static const struct hda_verb alc260_replacer_672v_verbs[] = {
-       {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-       {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
-
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
-
-       {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc260_replacer_672v_automute(struct hda_codec *codec)
-{
-        unsigned int present;
-
-       /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
-       present = snd_hda_jack_detect(codec, 0x0f);
-       if (present) {
-               snd_hda_codec_write_cache(codec, 0x01, 0,
-                                         AC_VERB_SET_GPIO_DATA, 1);
-               snd_hda_codec_write_cache(codec, 0x0f, 0,
-                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                         PIN_HP);
-       } else {
-               snd_hda_codec_write_cache(codec, 0x01, 0,
-                                         AC_VERB_SET_GPIO_DATA, 0);
-               snd_hda_codec_write_cache(codec, 0x0f, 0,
-                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                         PIN_OUT);
-       }
-}
-
-static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
-                                       unsigned int res)
-{
-        if ((res >> 26) == ALC880_HP_EVENT)
-                alc260_replacer_672v_automute(codec);
-}
-
-static const struct hda_verb alc260_hp_dc7600_verbs[] = {
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
-
-/* Test configuration for debugging, modelled after the ALC880 test
- * configuration.
- */
-#ifdef CONFIG_SND_DEBUG
-static const hda_nid_t alc260_test_dac_nids[1] = {
-       0x02,
-};
-static const hda_nid_t alc260_test_adc_nids[2] = {
-       0x04, 0x05,
-};
-/* For testing the ALC260, each input MUX needs its own definition since
- * the signal assignments are different.  This assumes that the first ADC
- * is NID 0x04.
- */
-static const struct hda_input_mux alc260_test_capture_sources[2] = {
-       {
-               .num_items = 7,
-               .items = {
-                       { "MIC1 pin", 0x0 },
-                       { "MIC2 pin", 0x1 },
-                       { "LINE1 pin", 0x2 },
-                       { "LINE2 pin", 0x3 },
-                       { "CD pin", 0x4 },
-                       { "LINE-OUT pin", 0x5 },
-                       { "HP-OUT pin", 0x6 },
-               },
-        },
-       {
-               .num_items = 8,
-               .items = {
-                       { "MIC1 pin", 0x0 },
-                       { "MIC2 pin", 0x1 },
-                       { "LINE1 pin", 0x2 },
-                       { "LINE2 pin", 0x3 },
-                       { "CD pin", 0x4 },
-                       { "Mixer", 0x5 },
-                       { "LINE-OUT pin", 0x6 },
-                       { "HP-OUT pin", 0x7 },
-               },
-        },
-};
-static const struct snd_kcontrol_new alc260_test_mixer[] = {
-       /* Output driver widgets */
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
-
-       /* Modes for retasking pin widgets
-        * Note: the ALC260 doesn't seem to act on requests to enable mic
-         * bias from NIDs 0x0f and 0x10.  The ALC260 datasheet doesn't
-         * mention this restriction.  At this stage it's not clear whether
-         * this behaviour is intentional or is a hardware bug in chip
-         * revisions available at least up until early 2006.  Therefore for
-         * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
-         * choices, but if it turns out that the lack of mic bias for these
-         * NIDs is intentional we could change their modes from
-         * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
-        */
-       ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
-       ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
-       ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
-       ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
-       ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
-       ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
-
-       /* Loopback mixer controls */
-       HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
-       HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
-
-       /* Controls for GPIO pins, assuming they are configured as outputs */
-       ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
-       ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
-       ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
-       ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
-
-       /* Switches to allow the digital IO pins to be enabled.  The datasheet
-        * is ambigious as to which NID is which; testing on laptops which
-        * make this output available should provide clarification.
-        */
-       ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
-       ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
-
-       /* A switch allowing EAPD to be enabled.  Some laptops seem to use
-        * this output to turn on an external amplifier.
-        */
-       ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
-       ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
-
-       { } /* end */
-};
-static const struct hda_verb alc260_test_init_verbs[] = {
-       /* Enable all GPIOs as outputs with an initial value of 0 */
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
-
-       /* Enable retasking pins as output, initially without power amp */
-       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       /* Disable digital (SPDIF) pins initially, but users can enable
-        * them via a mixer switch.  In the case of SPDIF-out, this initverb
-        * payload also sets the generation to 0, output to be in "consumer"
-        * PCM format, copyright asserted, no pre-emphasis and no validity
-        * control.
-        */
-       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
-       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
-       /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
-        * OUT1 sum bus when acting as an output.
-        */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* Start with output sum widgets muted and their output gains at min */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* Unmute retasking pin widget output buffers since the default
-        * state appears to be output.  As the pin mode is changed by the
-        * user the pin mode control will take care of enabling the pin's
-        * input/output buffers as needed.
-        */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Also unmute the mono-out pin widget */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Mute capture amp left and right */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       /* Set ADC connection select to match default mixer setting (mic1
-        * pin)
-        */
-       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Do the same for the second ADC: mute capture input amp and
-        * set ADC connection to mic1 pin
-        */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Mute all inputs to mixer widget (even unconnected ones) */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
-
-       { }
-};
-#endif
-
-#define alc260_pcm_analog_playback     alc880_pcm_analog_alt_playback
-#define alc260_pcm_analog_capture      alc880_pcm_analog_capture
-
-#define alc260_pcm_digital_playback    alc880_pcm_digital_playback
-#define alc260_pcm_digital_capture     alc880_pcm_digital_capture
-
-/*
- * for BIOS auto-configuration
- */
-
-static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
-                                       const char *pfx, int *vol_bits)
-{
-       hda_nid_t nid_vol;
-       unsigned long vol_val, sw_val;
-       int err;
-
-       if (nid >= 0x0f && nid < 0x11) {
-               nid_vol = nid - 0x7;
-               vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
-               sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-       } else if (nid == 0x11) {
-               nid_vol = nid - 0x7;
-               vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
-               sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
-       } else if (nid >= 0x12 && nid <= 0x15) {
-               nid_vol = 0x08;
-               vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
-               sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-       } else
-               return 0; /* N/A */
-
-       if (!(*vol_bits & (1 << nid_vol))) {
-               /* first control for the volume widget */
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
-               if (err < 0)
-                       return err;
-               *vol_bits |= (1 << nid_vol);
-       }
-       err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
-       if (err < 0)
-               return err;
-       return 1;
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid;
-       int err;
-       int vols = 0;
-
-       spec->multiout.num_dacs = 1;
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       spec->private_dac_nids[0] = 0x02;
-
-       nid = cfg->line_out_pins[0];
-       if (nid) {
-               const char *pfx;
-               if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
-                       pfx = "Master";
-               else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                       pfx = "Speaker";
-               else
-                       pfx = "Front";
-               err = alc260_add_playback_controls(spec, nid, pfx, &vols);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->speaker_pins[0];
-       if (nid) {
-               err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->hp_pins[0];
-       if (nid) {
-               err = alc260_add_playback_controls(spec, nid, "Headphone",
-                                                  &vols);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int alc260_auto_create_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
-}
-
-static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type,
-                                             int sel_idx)
-{
-       alc_set_pin_output(codec, nid, pin_type);
-       /* need the manual connection? */
-       if (nid >= 0x12) {
-               int idx = nid - 0x12;
-               snd_hda_codec_write(codec, idx + 0x0b, 0,
-                                   AC_VERB_SET_CONNECT_SEL, sel_idx);
-       }
-}
-
-static void alc260_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       nid = spec->autocfg.line_out_pins[0];
-       if (nid) {
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
-       }
-
-       nid = spec->autocfg.speaker_pins[0];
-       if (nid)
-               alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
-
-       nid = spec->autocfg.hp_pins[0];
-       if (nid)
-               alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
-}
-
-#define ALC260_PIN_CD_NID              0x16
-static void alc260_auto_init_analog_input(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               if (nid >= 0x12) {
-                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
-                       if (nid != ALC260_PIN_CD_NID &&
-                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
-                               snd_hda_codec_write(codec, nid, 0,
-                                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                                   AMP_OUT_MUTE);
-               }
-       }
-}
-
-#define alc260_auto_init_input_src     alc880_auto_init_input_src
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc260_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for
-        * front panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       /* mute analog inputs */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /*
-        * Set up output mixers (0x08 - 0x0a)
-        */
-       /* set vol=0 to output mixers */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       { }
-};
-
-static int alc260_parse_auto_config(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc260_ignore);
-       if (err < 0)
-               return err;
-       err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       if (!spec->kctls.list)
-               return 0; /* can't find valid BIOS pin config */
-       err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = 2;
-
-       if (spec->autocfg.dig_outs)
-               spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       add_verb(spec, alc260_volume_init_verbs);
-
-       spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux[0];
-
-       alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
-
-       return 1;
-}
-
-/* additional initialization for auto-configuration model */
-static void alc260_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc260_auto_init_multi_out(codec);
-       alc260_auto_init_analog_input(codec);
-       alc260_auto_init_input_src(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc260_loopbacks[] = {
-       { 0x07, HDA_INPUT, 0 },
-       { 0x07, HDA_INPUT, 1 },
-       { 0x07, HDA_INPUT, 2 },
-       { 0x07, HDA_INPUT, 3 },
-       { 0x07, HDA_INPUT, 4 },
-       { } /* end */
-};
-#endif
-
-/*
- * Pin config fixes
- */
-enum {
-       PINFIX_HP_DC5750,
-};
-
-static const struct alc_fixup alc260_fixups[] = {
-       [PINFIX_HP_DC5750] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x11, 0x90130110 }, /* speaker */
-                       { }
-               }
-       },
-};
-
-static const struct snd_pci_quirk alc260_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
-       {}
-};
-
-/*
- * ALC260 configurations
- */
-static const char * const alc260_models[ALC260_MODEL_LAST] = {
-       [ALC260_BASIC]          = "basic",
-       [ALC260_HP]             = "hp",
-       [ALC260_HP_3013]        = "hp-3013",
-       [ALC260_HP_DC7600]      = "hp-dc7600",
-       [ALC260_FUJITSU_S702X]  = "fujitsu",
-       [ALC260_ACER]           = "acer",
-       [ALC260_WILL]           = "will",
-       [ALC260_REPLACER_672V]  = "replacer",
-       [ALC260_FAVORIT100]     = "favorit100",
-#ifdef CONFIG_SND_DEBUG
-       [ALC260_TEST]           = "test",
-#endif
-       [ALC260_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk alc260_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
-       SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
-       SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
-       SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
-       SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
-       SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
-       SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
-       SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
-       SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
-       SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
-       SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
-       SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
-       SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
-       SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
-       SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
-       SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
-       SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
-       SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
-       SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
-       SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
-       {}
-};
-
-static const struct alc_config_preset alc260_presets[] = {
-       [ALC260_BASIC] = {
-               .mixers = { alc260_base_output_mixer,
-                           alc260_input_mixer },
-               .init_verbs = { alc260_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
-               .dac_nids = alc260_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
-               .adc_nids = alc260_dual_adc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .input_mux = &alc260_capture_source,
-       },
-       [ALC260_HP] = {
-               .mixers = { alc260_hp_output_mixer,
-                           alc260_input_mixer },
-               .init_verbs = { alc260_init_verbs,
-                               alc260_hp_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
-               .dac_nids = alc260_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
-               .adc_nids = alc260_adc_nids_alt,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .input_mux = &alc260_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc260_hp_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC260_HP_DC7600] = {
-               .mixers = { alc260_hp_dc7600_mixer,
-                           alc260_input_mixer },
-               .init_verbs = { alc260_init_verbs,
-                               alc260_hp_dc7600_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
-               .dac_nids = alc260_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
-               .adc_nids = alc260_adc_nids_alt,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .input_mux = &alc260_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc260_hp_3012_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC260_HP_3013] = {
-               .mixers = { alc260_hp_3013_mixer,
-                           alc260_input_mixer },
-               .init_verbs = { alc260_hp_3013_init_verbs,
-                               alc260_hp_3013_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
-               .dac_nids = alc260_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
-               .adc_nids = alc260_adc_nids_alt,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .input_mux = &alc260_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc260_hp_3013_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC260_FUJITSU_S702X] = {
-               .mixers = { alc260_fujitsu_mixer },
-               .init_verbs = { alc260_fujitsu_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
-               .dac_nids = alc260_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
-               .adc_nids = alc260_dual_adc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
-               .input_mux = alc260_fujitsu_capture_sources,
-       },
-       [ALC260_ACER] = {
-               .mixers = { alc260_acer_mixer },
-               .init_verbs = { alc260_acer_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
-               .dac_nids = alc260_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
-               .adc_nids = alc260_dual_adc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
-               .input_mux = alc260_acer_capture_sources,
-       },
-       [ALC260_FAVORIT100] = {
-               .mixers = { alc260_favorit100_mixer },
-               .init_verbs = { alc260_favorit100_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
-               .dac_nids = alc260_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
-               .adc_nids = alc260_dual_adc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
-               .input_mux = alc260_favorit100_capture_sources,
-       },
-       [ALC260_WILL] = {
-               .mixers = { alc260_will_mixer },
-               .init_verbs = { alc260_init_verbs, alc260_will_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
-               .dac_nids = alc260_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
-               .adc_nids = alc260_adc_nids,
-               .dig_out_nid = ALC260_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .input_mux = &alc260_capture_source,
-       },
-       [ALC260_REPLACER_672V] = {
-               .mixers = { alc260_replacer_672v_mixer },
-               .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
-               .dac_nids = alc260_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
-               .adc_nids = alc260_adc_nids,
-               .dig_out_nid = ALC260_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .input_mux = &alc260_capture_source,
-               .unsol_event = alc260_replacer_672v_unsol_event,
-               .init_hook = alc260_replacer_672v_automute,
-       },
-#ifdef CONFIG_SND_DEBUG
-       [ALC260_TEST] = {
-               .mixers = { alc260_test_mixer },
-               .init_verbs = { alc260_test_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
-               .dac_nids = alc260_test_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
-               .adc_nids = alc260_test_adc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc260_modes),
-               .channel_mode = alc260_modes,
-               .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
-               .input_mux = alc260_test_capture_sources,
-       },
-#endif
-};
-
-static int patch_alc260(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err, board_config;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
-                                                 alc260_models,
-                                                 alc260_cfg_tbl);
-       if (board_config < 0) {
-               snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                          codec->chip_name);
-               board_config = ALC260_AUTO;
-       }
-
-       if (board_config == ALC260_AUTO) {
-               alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
-               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-       }
-
-       if (board_config == ALC260_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc260_parse_auto_config(codec);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               } else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using base mode...\n");
-                       board_config = ALC260_BASIC;
-               }
-       }
-
-       err = snd_hda_attach_beep_device(codec, 0x1);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
-       }
-
-       if (board_config != ALC260_AUTO)
-               setup_preset(codec, &alc260_presets[board_config]);
-
-       spec->stream_analog_playback = &alc260_pcm_analog_playback;
-       spec->stream_analog_capture = &alc260_pcm_analog_capture;
-       spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
-
-       spec->stream_digital_playback = &alc260_pcm_digital_playback;
-       spec->stream_digital_capture = &alc260_pcm_digital_capture;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               /* check whether NID 0x04 is valid */
-               unsigned int wcap = get_wcaps(codec, 0x04);
-               wcap = get_wcaps_type(wcap);
-               /* get type */
-               if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
-                       spec->adc_nids = alc260_adc_nids_alt;
-                       spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
-               } else {
-                       spec->adc_nids = alc260_adc_nids;
-                       spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
-               }
-       }
-       set_capture_mixer(codec);
-       set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
-
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
-       spec->vmaster_nid = 0x08;
-
-       codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC260_AUTO)
-               spec->init_hook = alc260_auto_init;
-       spec->shutup = alc_eapd_shutup;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc260_loopbacks;
-#endif
-
-       return 0;
-}
-
-
-/*
- * ALC882/883/885/888/889 support
- *
- * ALC882 is almost identical with ALC880 but has cleaner and more flexible
- * configuration.  Each pin widget can choose any input DACs and a mixer.
- * Each ADC is connected from a mixer of all inputs.  This makes possible
- * 6-channel independent captures.
- *
- * In addition, an independent DAC for the multi-playback (not used in this
- * driver yet).
- */
-#define ALC882_DIGOUT_NID      0x06
-#define ALC882_DIGIN_NID       0x0a
-#define ALC883_DIGOUT_NID      ALC882_DIGOUT_NID
-#define ALC883_DIGIN_NID       ALC882_DIGIN_NID
-#define ALC1200_DIGOUT_NID     0x10
-
-
-static const struct hda_channel_mode alc882_ch_modes[1] = {
-       { 8, NULL }
-};
-
-/* DACs */
-static const hda_nid_t alc882_dac_nids[4] = {
-       /* front, rear, clfe, rear_surr */
-       0x02, 0x03, 0x04, 0x05
-};
-#define alc883_dac_nids                alc882_dac_nids
-
-/* ADCs */
-#define alc882_adc_nids                alc880_adc_nids
-#define alc882_adc_nids_alt    alc880_adc_nids_alt
-#define alc883_adc_nids                alc882_adc_nids_alt
-static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
-static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
-#define alc889_adc_nids                alc880_adc_nids
-
-static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
-static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
-#define alc883_capsrc_nids     alc882_capsrc_nids_alt
-static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
-#define alc889_capsrc_nids     alc882_capsrc_nids
-
-/* input MUX */
-/* FIXME: should be a matrix-type input source selection */
-
-static const struct hda_input_mux alc882_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-#define alc883_capture_source  alc882_capture_source
-
-static const struct hda_input_mux alc889_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Mic", 0x3 },
-               { "Line", 0x2 },
-       },
-};
-
-static const struct hda_input_mux mb5_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x1 },
-               { "Line", 0x7 },
-               { "CD", 0x4 },
-       },
-};
-
-static const struct hda_input_mux macmini3_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-static const struct hda_input_mux alc883_3stack_6ch_intel = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x1 },
-               { "Front Mic", 0x0 },
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x1 },
-               { "Line", 0x2 },
-       },
-};
-
-static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-       },
-};
-
-static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x4 },
-       },
-};
-
-static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               { "Line", 0x2 },
-       },
-};
-
-static const struct hda_input_mux alc889A_mb31_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               /* Front Mic (0x01) unused */
-               { "Line", 0x2 },
-               /* Line 2 (0x03) unused */
-               /* CD (0x04) unused? */
-       },
-};
-
-static const struct hda_input_mux alc889A_imac91_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x01 },
-               { "Line", 0x2 }, /* Not sure! */
-       },
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
-       { 2, NULL }
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc882_3ST_ch2_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc882_3ST_ch4_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc882_3ST_ch6_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
-       { 2, alc882_3ST_ch2_init },
-       { 4, alc882_3ST_ch4_init },
-       { 6, alc882_3ST_ch6_init },
-};
-
-#define alc883_3ST_6ch_modes   alc882_3ST_6ch_modes
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
-       { 2, alc883_3ST_ch2_clevo_init },
-       { 4, alc883_3ST_ch4_clevo_init },
-       { 6, alc883_3ST_ch6_clevo_init },
-};
-
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc882_sixstack_ch6_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc882_sixstack_ch8_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc882_sixstack_modes[2] = {
-       { 6, alc882_sixstack_ch6_init },
-       { 8, alc882_sixstack_ch8_init },
-};
-
-
-/* Macbook Air 2,1 */
-
-static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
-      { 2, NULL },
-};
-
-/*
- * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
- */
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc885_mbp_ch2_init[] = {
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc885_mbp_ch4_init[] = {
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
-       { 2, alc885_mbp_ch2_init },
-       { 4, alc885_mbp_ch4_init },
-};
-
-/*
- * 2ch
- * Speakers/Woofer/HP = Front
- * LineIn = Input
- */
-static const struct hda_verb alc885_mb5_ch2_init[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       { } /* end */
-};
-
-/*
- * 6ch mode
- * Speakers/HP = Front
- * Woofer = LFE
- * LineIn = Surround
- */
-static const struct hda_verb alc885_mb5_ch6_init[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
-       { 2, alc885_mb5_ch2_init },
-       { 6, alc885_mb5_ch6_init },
-};
-
-#define alc885_macmini3_6ch_modes      alc885_mb5_6ch_modes
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc883_4ST_ch2_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc883_4ST_ch4_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_4ST_ch6_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc883_4ST_ch8_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
-       { 2, alc883_4ST_ch2_init },
-       { 4, alc883_4ST_ch4_init },
-       { 6, alc883_4ST_ch6_init },
-       { 8, alc883_4ST_ch8_init },
-};
-
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
-       { 2, alc883_3ST_ch2_intel_init },
-       { 4, alc883_3ST_ch4_intel_init },
-       { 6, alc883_3ST_ch6_intel_init },
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc889_ch2_intel_init[] = {
-       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc889_ch6_intel_init[] = {
-       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc889_ch8_intel_init[] = {
-       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
-       { 2, alc889_ch2_intel_init },
-       { 6, alc889_ch6_intel_init },
-       { 8, alc889_ch8_intel_init },
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_sixstack_ch6_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc883_sixstack_ch8_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc883_sixstack_modes[2] = {
-       { 6, alc883_sixstack_ch6_init },
-       { 8, alc883_sixstack_ch8_init },
-};
-
-
-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
- *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
- */
-static const struct snd_kcontrol_new alc882_base_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-/* Macbook Air 2,1 same control for HP and internal Speaker */
-
-static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
-      HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-      HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
-     { }
-};
-
-
-static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
-       { } /* end */
-};
-
-
-static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc882_targa_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
- *                 Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
- */
-static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb alc882_base_init_verbs[] = {
-       /* Front mixer: unmute input/output amp left and right (volume = 0) */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Rear mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* CLFE mixer */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Side mixer */
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-       /* Front Pin: output 0 (0x0c) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Rear Pin: output 1 (0x0d) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* CLFE Pin: output 2 (0x0e) */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* Side Pin: output 3 (0x0f) */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-       /* Mic (rear) pin: input vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Front Mic pin: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin: input */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line-2 In: Headphone output (output 0 - 0x0c) */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* CD pin widget for input */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* ADC2: mute amp left and right */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC3: mute amp left and right */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       { }
-};
-
-static const struct hda_verb alc882_adc1_init_verbs[] = {
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* ADC1: mute amp left and right */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { }
-};
-
-static const struct hda_verb alc882_eapd_verbs[] = {
-       /* change to EAPD mode */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
-       { }
-};
-
-static const struct hda_verb alc889_eapd_verbs[] = {
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-static const struct hda_verb alc_hp15_unsol_verbs[] = {
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const struct hda_verb alc885_init_verbs[] = {
-       /* Front mixer: unmute input/output amp left and right (volume = 0) */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Rear mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* CLFE mixer */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Side mixer */
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* Front HP Pin: output 0 (0x0c) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Front Pin: output 0 (0x0c) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Rear Pin: output 1 (0x0d) */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* CLFE Pin: output 2 (0x0e) */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* Side Pin: output 3 (0x0f) */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-       /* Mic (rear) pin: input vref at 80% */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Front Mic pin: input vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin: input */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       /* Mixer elements: 0x18, , 0x1a, 0x1b */
-       /* Input mixer1 */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* ADC2: mute amp left and right */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       /* ADC3: mute amp left and right */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-
-       { }
-};
-
-static const struct hda_verb alc885_init_input_verbs[] = {
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       { }
-};
-
-
-/* Unmute Selector 24h and set the default input to front mic */
-static const struct hda_verb alc889_init_input_verbs[] = {
-       {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       { }
-};
-
-
-#define alc883_init_verbs      alc882_base_init_verbs
-
-/* Mac Pro test */
-static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       /* FIXME: this looks suspicious...
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       */
-       { } /* end */
-};
-
-static const struct hda_verb alc882_macpro_init_verbs[] = {
-       /* Front mixer: unmute input/output amp left and right (volume = 0) */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Front Pin: output 0 (0x0c) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Front Mic pin: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Speaker:  output */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
-       /* Headphone output (output 0 - 0x0c) */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* ADC1: mute amp left and right */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC2: mute amp left and right */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC3: mute amp left and right */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       { }
-};
-
-/* Macbook 5,1 */
-static const struct hda_verb alc885_mb5_init_verbs[] = {
-       /* DACs */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Front mixer */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Surround mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* LFE mixer */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* HP mixer */
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Front Pin (0x0c) */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* LFE Pin (0x0e) */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* HP Pin (0x0f) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       /* Front Mic pin: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
-       { }
-};
-
-/* Macmini 3,1 */
-static const struct hda_verb alc885_macmini3_init_verbs[] = {
-       /* DACs */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Front mixer */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Surround mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* LFE mixer */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* HP mixer */
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Front Pin (0x0c) */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* LFE Pin (0x0e) */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* HP Pin (0x0f) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       /* Line In pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       { }
-};
-
-
-static const struct hda_verb alc885_mba21_init_verbs[] = {
-       /*Internal and HP Speaker Mixer*/
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /*Internal Speaker Pin (0x0c)*/
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* HP Pin: output 0 (0x0e) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
-       /* Line in (is hp when jack connected)*/
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       { }
- };
-
-
-/* Macbook Pro rev3 */
-static const struct hda_verb alc885_mbp3_init_verbs[] = {
-       /* Front mixer: unmute input/output amp left and right (volume = 0) */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Rear mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* HP mixer */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Front Pin: output 0 (0x0c) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* HP Pin: output 0 (0x0e) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       /* Mic (rear) pin: input vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Front Mic pin: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin: use output 1 when in LineOut mode */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* ADC1: mute amp left and right */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC2: mute amp left and right */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC3: mute amp left and right */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       { }
-};
-
-/* iMac 9,1 */
-static const struct hda_verb alc885_imac91_init_verbs[] = {
-       /* Internal Speaker Pin (0x0c) */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* HP Pin: Rear */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
-       /* Line in Rear */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Front Mic pin: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Rear mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { }
-};
-
-/* iMac 24 mixer. */
-static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
-       { } /* end */
-};
-
-/* iMac 24 init verbs. */
-static const struct hda_verb alc885_imac24_init_verbs[] = {
-       /* Internal speakers: output 0 (0x0c) */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Internal speakers: output 0 (0x0c) */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Headphone: output 0 (0x0c) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       /* Front Mic: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       { }
-};
-
-/* Toggle speaker-output according to the hp-jack state */
-static void alc885_imac24_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x18;
-       spec->autocfg.speaker_pins[1] = 0x1a;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-#define alc885_mb5_setup       alc885_imac24_setup
-#define alc885_macmini3_setup  alc885_imac24_setup
-
-/* Macbook Air 2,1 */
-static void alc885_mba21_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x18;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-
-
-static void alc885_mbp3_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc885_imac91_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x18;
-       spec->autocfg.speaker_pins[1] = 0x1a;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc882_targa_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc882_targa_automute(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_hp_automute(codec);
-       snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
-                                 spec->jack_present ? 1 : 3);
-}
-
-static void alc882_targa_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x1b;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc882_targa_automute(codec);
-}
-
-static const struct hda_verb alc882_asus_a7j_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       { } /* end */
-};
-
-static const struct hda_verb alc882_asus_a7m_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       { } /* end */
-};
-
-static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
-{
-       unsigned int gpiostate, gpiomask, gpiodir;
-
-       gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
-                                      AC_VERB_GET_GPIO_DATA, 0);
-
-       if (!muted)
-               gpiostate |= (1 << pin);
-       else
-               gpiostate &= ~(1 << pin);
-
-       gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
-                                     AC_VERB_GET_GPIO_MASK, 0);
-       gpiomask |= (1 << pin);
-
-       gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
-                                    AC_VERB_GET_GPIO_DIRECTION, 0);
-       gpiodir |= (1 << pin);
-
-
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_MASK, gpiomask);
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DIRECTION, gpiodir);
-
-       msleep(1);
-
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DATA, gpiostate);
-}
-
-/* set up GPIO at initialization */
-static void alc885_macpro_init_hook(struct hda_codec *codec)
-{
-       alc882_gpio_mute(codec, 0, 0);
-       alc882_gpio_mute(codec, 1, 0);
-}
-
-/* set up GPIO and update auto-muting at initialization */
-static void alc885_imac24_init_hook(struct hda_codec *codec)
-{
-       alc885_macpro_init_hook(codec);
-       alc_hp_automute(codec);
-}
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc883_auto_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /*
-        * Set up output mixers (0x0c - 0x0f)
-        */
-       /* set vol=0 to output mixers */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { }
-};
-
-/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
-static const struct hda_verb alc889A_mb31_ch2_init[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Line off */
-       { } /* end */
-};
-
-/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
-static const struct hda_verb alc889A_mb31_ch4_init[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
-       { } /* end */
-};
-
-/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
-static const struct hda_verb alc889A_mb31_ch5_init[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as rear */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Line off */
-       { } /* end */
-};
-
-/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
-static const struct hda_verb alc889A_mb31_ch6_init[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as front */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Subwoofer off */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
-       { 2, alc889A_mb31_ch2_init },
-       { 4, alc889A_mb31_ch4_init },
-       { 5, alc889A_mb31_ch5_init },
-       { 6, alc889A_mb31_ch6_init },
-};
-
-static const struct hda_verb alc883_medion_eapd_verbs[] = {
-        /* eanable EAPD on medion laptop */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
-       { }
-};
-
-#define alc883_base_mixer      alc882_base_mixer
-
-static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-                             HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-                             HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_targa_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc883_medion_wim2160_verbs[] = {
-       /* Unmute front mixer */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* Set speaker pin to front mixer */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Init headphone pin */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_medion_wim2160_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1a;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume",
-                                               0x0d, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
-       /* Output mixers */
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
-               HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
-       /* Output switches */
-       HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
-       /* Boost mixers */
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
-       /* Input mixers */
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_bind_ctls alc883_bind_cap_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
-               0
-       },
-};
-
-static const struct hda_bind_ctls alc883_bind_cap_switch = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
-               0
-       },
-};
-
-static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
-       HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
-       HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = alc_mux_enum_info,
-               .get = alc_mux_enum_get,
-               .put = alc_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_mitac_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x17;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc883_mitac_verbs[] = {
-       /* HP */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Subwoofer */
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       /* enable unsolicited event */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_clevo_m540r_verbs[] = {
-       /* HP */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Int speaker */
-       /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
-
-       /* enable unsolicited event */
-       /*
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
-       */
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_clevo_m720_verbs[] = {
-       /* HP */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Int speaker */
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       /* enable unsolicited event */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
-       /* HP */
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Subwoofer */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       /* enable unsolicited event */
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_targa_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-/* Connect Line-Out side jack (SPDIF) to Side */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-/* Connect Mic jack to CLFE */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
-/* Connect Line-in jack to Surround */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-/* Connect HP out jack to Front */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_lenovo_101e_verbs[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
-        {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
-       { } /* end */
-};
-
-static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
-        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       { } /* end */
-};
-
-static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT    | AC_USRSP_EN},
-       { } /* end */
-};
-
-static const struct hda_verb alc883_haier_w66_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       { } /* end */
-};
-
-static const struct hda_verb alc888_lenovo_sky_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
-static const struct hda_verb alc888_6st_dell_verbs[] = {
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { }
-};
-
-static const struct hda_verb alc883_vaiott_verbs[] = {
-       /* HP */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
-       /* enable unsolicited event */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-static void alc888_3st_hp_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x18;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc888_3st_hp_verbs[] = {
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Rear : output 1 (0x0d) */
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},  /* CLFE : output 2 (0x0e) */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc888_3st_hp_2ch_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc888_3st_hp_4ch_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc888_3st_hp_6ch_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
-       { 2, alc888_3st_hp_2ch_init },
-       { 4, alc888_3st_hp_4ch_init },
-       { 6, alc888_3st_hp_6ch_init },
-};
-
-static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.line_out_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/* toggle speaker-output according to the hp-jack state */
-#define alc883_targa_init_hook         alc882_targa_init_hook
-#define alc883_targa_unsol_event       alc882_targa_unsol_event
-
-static void alc883_clevo_m720_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
-{
-       alc_hp_automute(codec);
-       alc88x_simple_mic_automute(codec);
-}
-
-static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
-                                          unsigned int res)
-{
-       switch (res >> 26) {
-       case ALC880_MIC_EVENT:
-               alc88x_simple_mic_automute(codec);
-               break;
-       default:
-               alc_sku_unsol_event(codec, res);
-               break;
-       }
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc883_haier_w66_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc883_lenovo_101e_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.line_out_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->detect_line = 1;
-       spec->automute_lines = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_acer_aspire_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc883_acer_eapd_verbs[] = {
-       /* HP Pin: output 0 (0x0c) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Front Pin: output 0 (0x0c) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
-        /* eanable EAPD on medion laptop */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
-       /* enable unsolicited event */
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { }
-};
-
-static void alc888_6st_dell_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x15;
-       spec->autocfg.speaker_pins[2] = 0x16;
-       spec->autocfg.speaker_pins[3] = 0x17;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc888_lenovo_sky_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x15;
-       spec->autocfg.speaker_pins[2] = 0x16;
-       spec->autocfg.speaker_pins[3] = 0x17;
-       spec->autocfg.speaker_pins[4] = 0x1a;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc883_vaiott_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x17;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc888_asus_m90v_verbs[] = {
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* enable unsolicited event */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
-static void alc883_mode2_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x15;
-       spec->autocfg.speaker_pins[2] = 0x16;
-       spec->ext_mic.pin = 0x18;
-       spec->int_mic.pin = 0x19;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc888_asus_eee1601_verbs[] = {
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x0838},
-       /* enable unsolicited event */
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
-static void alc883_eee1601_inithook(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x1b;
-       alc_hp_automute(codec);
-}
-
-static const struct hda_verb alc889A_mb31_verbs[] = {
-       /* Init rear pin (used as headphone output) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},    /* Apple Headphones */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},           /* Connect to front */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       /* Init line pin (used as output in 4ch and 6ch mode) */
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},           /* Connect to CLFE */
-       /* Init line 2 pin (used as headphone out by default) */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},  /* Use as input */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
-       { } /* end */
-};
-
-/* Mute speakers according to the headphone jack state */
-static void alc889A_mb31_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       /* Mute only in 2ch or 4ch mode */
-       if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
-           == 0x00) {
-               present = snd_hda_jack_detect(codec, 0x15);
-               snd_hda_codec_amp_stereo(codec, 0x14,  HDA_OUTPUT, 0,
-                       HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-               snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                       HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       }
-}
-
-static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc889A_mb31_automute(codec);
-}
-
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc882_loopbacks       alc880_loopbacks
-#endif
-
-/* pcm configuration: identical with ALC880 */
-#define alc882_pcm_analog_playback     alc880_pcm_analog_playback
-#define alc882_pcm_analog_capture      alc880_pcm_analog_capture
-#define alc882_pcm_digital_playback    alc880_pcm_digital_playback
-#define alc882_pcm_digital_capture     alc880_pcm_digital_capture
-
-static const hda_nid_t alc883_slave_dig_outs[] = {
-       ALC1200_DIGOUT_NID, 0,
-};
-
-static const hda_nid_t alc1200_slave_dig_outs[] = {
-       ALC883_DIGOUT_NID, 0,
-};
-
-/*
- * configuration and preset
- */
-static const char * const alc882_models[ALC882_MODEL_LAST] = {
-       [ALC882_3ST_DIG]        = "3stack-dig",
-       [ALC882_6ST_DIG]        = "6stack-dig",
-       [ALC882_ARIMA]          = "arima",
-       [ALC882_W2JC]           = "w2jc",
-       [ALC882_TARGA]          = "targa",
-       [ALC882_ASUS_A7J]       = "asus-a7j",
-       [ALC882_ASUS_A7M]       = "asus-a7m",
-       [ALC885_MACPRO]         = "macpro",
-       [ALC885_MB5]            = "mb5",
-       [ALC885_MACMINI3]       = "macmini3",
-       [ALC885_MBA21]          = "mba21",
-       [ALC885_MBP3]           = "mbp3",
-       [ALC885_IMAC24]         = "imac24",
-       [ALC885_IMAC91]         = "imac91",
-       [ALC883_3ST_2ch_DIG]    = "3stack-2ch-dig",
-       [ALC883_3ST_6ch_DIG]    = "3stack-6ch-dig",
-       [ALC883_3ST_6ch]        = "3stack-6ch",
-       [ALC883_6ST_DIG]        = "alc883-6stack-dig",
-       [ALC883_TARGA_DIG]      = "targa-dig",
-       [ALC883_TARGA_2ch_DIG]  = "targa-2ch-dig",
-       [ALC883_TARGA_8ch_DIG]  = "targa-8ch-dig",
-       [ALC883_ACER]           = "acer",
-       [ALC883_ACER_ASPIRE]    = "acer-aspire",
-       [ALC888_ACER_ASPIRE_4930G]      = "acer-aspire-4930g",
-       [ALC888_ACER_ASPIRE_6530G]      = "acer-aspire-6530g",
-       [ALC888_ACER_ASPIRE_8930G]      = "acer-aspire-8930g",
-       [ALC888_ACER_ASPIRE_7730G]      = "acer-aspire-7730g",
-       [ALC883_MEDION]         = "medion",
-       [ALC883_MEDION_WIM2160] = "medion-wim2160",
-       [ALC883_LAPTOP_EAPD]    = "laptop-eapd",
-       [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
-       [ALC883_LENOVO_NB0763]  = "lenovo-nb0763",
-       [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
-       [ALC888_LENOVO_SKY] = "lenovo-sky",
-       [ALC883_HAIER_W66]      = "haier-w66",
-       [ALC888_3ST_HP]         = "3stack-hp",
-       [ALC888_6ST_DELL]       = "6stack-dell",
-       [ALC883_MITAC]          = "mitac",
-       [ALC883_CLEVO_M540R]    = "clevo-m540r",
-       [ALC883_CLEVO_M720]     = "clevo-m720",
-       [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
-       [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
-       [ALC883_3ST_6ch_INTEL]  = "3stack-6ch-intel",
-       [ALC889A_INTEL]         = "intel-alc889a",
-       [ALC889_INTEL]          = "intel-x58",
-       [ALC1200_ASUS_P5Q]      = "asus-p5q",
-       [ALC889A_MB31]          = "mb31",
-       [ALC883_SONY_VAIO_TT]   = "sony-vaio-tt",
-       [ALC882_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk alc882_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
-
-       SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
-               ALC888_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
-               ALC888_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
-               ALC888_ACER_ASPIRE_8930G),
-       SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
-               ALC888_ACER_ASPIRE_8930G),
-       SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
-       SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
-       SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
-               ALC888_ACER_ASPIRE_6530G),
-       SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
-               ALC888_ACER_ASPIRE_6530G),
-       SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
-               ALC888_ACER_ASPIRE_7730G),
-       /* default Acer -- disabled as it causes more problems.
-        *    model=auto should work fine now
-        */
-       /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
-
-       SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
-
-       SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
-       SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
-       SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
-       SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
-
-       SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
-       SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
-       SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
-       SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
-       SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
-       SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
-       SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
-
-       SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
-       SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
-       SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
-       SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
-       SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
-       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
-
-       SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
-       SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
-       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
-
-       SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
-       SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
-       SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
-       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
-       /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
-       SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
-       SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
-                     ALC883_FUJITSU_PI2515),
-       SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
-               ALC888_FUJITSU_XA3530),
-       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
-       SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-       SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-       SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-       SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
-       SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
-       SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
-
-       SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
-       SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
-       SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
-       SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
-       SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
-       SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
-       SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
-
-       {}
-};
-
-/* codec SSID table for Intel Mac */
-static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
-       SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
-       SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
-       SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
-       SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
-       SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
-       SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
-       SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
-       SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
-       SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
-       SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
-       SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
-       SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
-       SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
-       SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
-       SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
-       SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
-       /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
-        * so apparently no perfect solution yet
-        */
-       SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
-       SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
-       SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
-       {} /* terminator */
-};
-
-static const struct alc_config_preset alc882_presets[] = {
-       [ALC882_3ST_DIG] = {
-               .mixers = { alc882_base_mixer },
-               .init_verbs = { alc882_base_init_verbs,
-                               alc882_adc1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
-               .channel_mode = alc882_ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC882_6ST_DIG] = {
-               .mixers = { alc882_base_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs,
-                               alc882_adc1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
-               .channel_mode = alc882_sixstack_modes,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC882_ARIMA] = {
-               .mixers = { alc882_base_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc882_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
-               .channel_mode = alc882_sixstack_modes,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC882_W2JC] = {
-               .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc882_eapd_verbs, alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-               .channel_mode = alc880_threestack_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc882_capture_source,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-       },
-          [ALC885_MBA21] = {
-                       .mixers = { alc885_mba21_mixer },
-                       .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
-                       .num_dacs = 2,
-                       .dac_nids = alc882_dac_nids,
-                       .channel_mode = alc885_mba21_ch_modes,
-                       .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
-                       .input_mux = &alc882_capture_source,
-                       .unsol_event = alc_sku_unsol_event,
-                       .setup = alc885_mba21_setup,
-                       .init_hook = alc_hp_automute,
-       },
-       [ALC885_MBP3] = {
-               .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc885_mbp3_init_verbs,
-                               alc880_gpio1_init_verbs },
-               .num_dacs = 2,
-               .dac_nids = alc882_dac_nids,
-               .hp_nid = 0x04,
-               .channel_mode = alc885_mbp_4ch_modes,
-               .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
-               .input_mux = &alc882_capture_source,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc885_mbp3_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC885_MB5] = {
-               .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc885_mb5_init_verbs,
-                               alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .channel_mode = alc885_mb5_6ch_modes,
-               .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
-               .input_mux = &mb5_capture_source,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc885_mb5_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC885_MACMINI3] = {
-               .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc885_macmini3_init_verbs,
-                               alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .channel_mode = alc885_macmini3_6ch_modes,
-               .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
-               .input_mux = &macmini3_capture_source,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc885_macmini3_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC885_MACPRO] = {
-               .mixers = { alc882_macpro_mixer },
-               .init_verbs = { alc882_macpro_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
-               .channel_mode = alc882_ch_modes,
-               .input_mux = &alc882_capture_source,
-               .init_hook = alc885_macpro_init_hook,
-       },
-       [ALC885_IMAC24] = {
-               .mixers = { alc885_imac24_mixer },
-               .init_verbs = { alc885_imac24_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
-               .channel_mode = alc882_ch_modes,
-               .input_mux = &alc882_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc885_imac24_setup,
-               .init_hook = alc885_imac24_init_hook,
-       },
-       [ALC885_IMAC91] = {
-               .mixers = {alc885_imac91_mixer},
-               .init_verbs = { alc885_imac91_init_verbs,
-                               alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .channel_mode = alc885_mba21_ch_modes,
-               .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
-               .input_mux = &alc889A_imac91_capture_source,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc885_imac91_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC882_TARGA] = {
-               .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc880_gpio3_init_verbs, alc882_targa_verbs},
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
-               .adc_nids = alc882_adc_nids,
-               .capsrc_nids = alc882_capsrc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
-               .channel_mode = alc882_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc882_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc882_targa_setup,
-               .init_hook = alc882_targa_automute,
-       },
-       [ALC882_ASUS_A7J] = {
-               .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc882_asus_a7j_verbs},
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
-               .adc_nids = alc882_adc_nids,
-               .capsrc_nids = alc882_capsrc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
-               .channel_mode = alc882_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC882_ASUS_A7M] = {
-               .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc882_eapd_verbs, alc880_gpio1_init_verbs,
-                               alc882_asus_a7m_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-               .channel_mode = alc880_threestack_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC883_3ST_2ch_DIG] = {
-               .mixers = { alc883_3ST_2ch_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_3ST_6ch_DIG] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_3ST_6ch] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_3ST_6ch_INTEL] = {
-               .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .slave_dig_outs = alc883_slave_dig_outs,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
-               .channel_mode = alc883_3ST_6ch_intel_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_3stack_6ch_intel,
-       },
-       [ALC889A_INTEL] = {
-               .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
-                               alc_hp15_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
-               .adc_nids = alc889_adc_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .slave_dig_outs = alc883_slave_dig_outs,
-               .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
-               .channel_mode = alc889_8ch_intel_modes,
-               .capsrc_nids = alc889_capsrc_nids,
-               .input_mux = &alc889_capture_source,
-               .setup = alc889_automute_setup,
-               .init_hook = alc_hp_automute,
-               .unsol_event = alc_sku_unsol_event,
-               .need_dac_fix = 1,
-       },
-       [ALC889_INTEL] = {
-               .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
-                               alc889_eapd_verbs, alc_hp15_unsol_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
-               .adc_nids = alc889_adc_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .slave_dig_outs = alc883_slave_dig_outs,
-               .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
-               .channel_mode = alc889_8ch_intel_modes,
-               .capsrc_nids = alc889_capsrc_nids,
-               .input_mux = &alc889_capture_source,
-               .setup = alc889_automute_setup,
-               .init_hook = alc889_intel_init_hook,
-               .unsol_event = alc_sku_unsol_event,
-               .need_dac_fix = 1,
-       },
-       [ALC883_6ST_DIG] = {
-               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_TARGA_DIG] = {
-               .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
-                               alc883_targa_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_targa_unsol_event,
-               .setup = alc882_targa_setup,
-               .init_hook = alc882_targa_automute,
-       },
-       [ALC883_TARGA_2ch_DIG] = {
-               .mixers = { alc883_targa_2ch_mixer},
-               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
-                               alc883_targa_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .adc_nids = alc883_adc_nids_alt,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
-               .capsrc_nids = alc883_capsrc_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_targa_unsol_event,
-               .setup = alc882_targa_setup,
-               .init_hook = alc882_targa_automute,
-       },
-       [ALC883_TARGA_8ch_DIG] = {
-               .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
-                           alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
-                               alc883_targa_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
-               .channel_mode = alc883_4ST_8ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_targa_unsol_event,
-               .setup = alc882_targa_setup,
-               .init_hook = alc882_targa_automute,
-       },
-       [ALC883_ACER] = {
-               .mixers = { alc883_base_mixer },
-               /* On TravelMate laptops, GPIO 0 enables the internal speaker
-                * and the headphone jack.  Turn this on and rely on the
-                * standard mute methods whenever the user wants to turn
-                * these outputs off.
-                */
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_ACER_ASPIRE] = {
-               .mixers = { alc883_acer_aspire_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_acer_aspire_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_ACER_ASPIRE_4930G] = {
-               .mixers = { alc888_acer_aspire_4930g_mixer,
-                               alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
-                               alc888_acer_aspire_4930g_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .const_channel_count = 6,
-               .num_mux_defs =
-                       ARRAY_SIZE(alc888_2_capture_sources),
-               .input_mux = alc888_2_capture_sources,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_acer_aspire_4930g_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_ACER_ASPIRE_6530G] = {
-               .mixers = { alc888_acer_aspire_6530_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
-                               alc888_acer_aspire_6530g_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .num_mux_defs =
-                       ARRAY_SIZE(alc888_2_capture_sources),
-               .input_mux = alc888_acer_aspire_6530_sources,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_acer_aspire_6530g_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_ACER_ASPIRE_8930G] = {
-               .mixers = { alc889_acer_aspire_8930g_mixer,
-                               alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
-                               alc889_acer_aspire_8930g_verbs,
-                               alc889_eapd_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
-               .adc_nids = alc889_adc_nids,
-               .capsrc_nids = alc889_capsrc_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .const_channel_count = 6,
-               .num_mux_defs =
-                       ARRAY_SIZE(alc889_capture_sources),
-               .input_mux = alc889_capture_sources,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc889_acer_aspire_8930g_setup,
-               .init_hook = alc_hp_automute,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-               .power_hook = alc_power_eapd,
-#endif
-       },
-       [ALC888_ACER_ASPIRE_7730G] = {
-               .mixers = { alc883_3ST_6ch_mixer,
-                               alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
-                               alc888_acer_aspire_7730G_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .const_channel_count = 6,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_acer_aspire_7730g_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC883_MEDION] = {
-               .mixers = { alc883_fivestack_mixer,
-                           alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs,
-                               alc883_medion_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .adc_nids = alc883_adc_nids_alt,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
-               .capsrc_nids = alc883_capsrc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_MEDION_WIM2160] = {
-               .mixers = { alc883_medion_wim2160_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_medion_wim2160_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC883_LAPTOP_EAPD] = {
-               .mixers = { alc883_base_mixer },
-               .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_CLEVO_M540R] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
-               .channel_mode = alc883_3ST_6ch_clevo_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               /* This machine has the hardware HP auto-muting, thus
-                * we need no software mute via unsol event
-                */
-       },
-       [ALC883_CLEVO_M720] = {
-               .mixers = { alc883_clevo_m720_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_clevo_m720_unsol_event,
-               .setup = alc883_clevo_m720_setup,
-               .init_hook = alc883_clevo_m720_init_hook,
-       },
-       [ALC883_LENOVO_101E_2ch] = {
-               .mixers = { alc883_lenovo_101e_2ch_mixer},
-               .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .adc_nids = alc883_adc_nids_alt,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
-               .capsrc_nids = alc883_capsrc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_lenovo_101e_capture_source,
-               .setup = alc883_lenovo_101e_setup,
-               .unsol_event = alc_sku_unsol_event,
-               .init_hook = alc_inithook,
-       },
-       [ALC883_LENOVO_NB0763] = {
-               .mixers = { alc883_lenovo_nb0763_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_lenovo_nb0763_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_lenovo_nb0763_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_LENOVO_MS7195_DIG] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_lenovo_ms7195_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC883_HAIER_W66] = {
-               .mixers = { alc883_targa_2ch_mixer},
-               .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_haier_w66_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_3ST_HP] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
-               .channel_mode = alc888_3st_hp_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_3st_hp_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_6ST_DELL] = {
-               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_6st_dell_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC883_MITAC] = {
-               .mixers = { alc883_mitac_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_mitac_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC883_FUJITSU_PI2515] = {
-               .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
-               .init_verbs = { alc883_init_verbs,
-                               alc883_2ch_fujitsu_pi2515_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_fujitsu_pi2515_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_2ch_fujitsu_pi2515_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_FUJITSU_XA3530] = {
-               .mixers = { alc888_base_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs,
-                       alc888_fujitsu_xa3530_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
-               .channel_mode = alc888_4ST_8ch_intel_modes,
-               .num_mux_defs =
-                       ARRAY_SIZE(alc888_2_capture_sources),
-               .input_mux = alc888_2_capture_sources,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_fujitsu_xa3530_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_LENOVO_SKY] = {
-               .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_lenovo_sky_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_lenovo_sky_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_ASUS_M90V] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_fujitsu_pi2515_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_mode2_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC888_ASUS_EEE1601] = {
-               .mixers = { alc883_asus_eee1601_mixer },
-               .cap_mixer = alc883_asus_eee1601_cap_mixer,
-               .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_asus_eee1601_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .init_hook = alc883_eee1601_inithook,
-       },
-       [ALC1200_ASUS_P5Q] = {
-               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC1200_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .slave_dig_outs = alc1200_slave_dig_outs,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC889A_MB31] = {
-               .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
-               .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
-                       alc880_gpio1_init_verbs },
-               .adc_nids = alc883_adc_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .capsrc_nids = alc883_capsrc_nids,
-               .dac_nids = alc883_dac_nids,
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .channel_mode = alc889A_mb31_6ch_modes,
-               .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
-               .input_mux = &alc889A_mb31_capture_source,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .unsol_event = alc889A_mb31_unsol_event,
-               .init_hook = alc889A_mb31_automute,
-       },
-       [ALC883_SONY_VAIO_TT] = {
-               .mixers = { alc883_vaiott_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_vaiott_setup,
-               .init_hook = alc_hp_automute,
-       },
-};
-
-
-/*
- * Pin config fixes
- */
-enum {
-       PINFIX_ABIT_AW9D_MAX,
-       PINFIX_LENOVO_Y530,
-       PINFIX_PB_M5210,
-       PINFIX_ACER_ASPIRE_7736,
-};
-
-static const struct alc_fixup alc882_fixups[] = {
-       [PINFIX_ABIT_AW9D_MAX] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x15, 0x01080104 }, /* side */
-                       { 0x16, 0x01011012 }, /* rear */
-                       { 0x17, 0x01016011 }, /* clfe */
-                       { }
-               }
-       },
-       [PINFIX_LENOVO_Y530] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x15, 0x99130112 }, /* rear int speakers */
-                       { 0x16, 0x99130111 }, /* subwoofer */
-                       { }
-               }
-       },
-       [PINFIX_PB_M5210] = {
-               .type = ALC_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
-                       {}
-               }
-       },
-       [PINFIX_ACER_ASPIRE_7736] = {
-               .type = ALC_FIXUP_SKU,
-               .v.sku = ALC_FIXUP_SKU_IGNORE,
-       },
-};
-
-static const struct snd_pci_quirk alc882_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
-       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
-       SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
-       SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
-       {}
-};
-
-/*
- * BIOS auto configuration
- */
-static int alc882_auto_create_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
-}
-
-static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type,
-                                             hda_nid_t dac)
-{
-       int idx;
-
-       /* set as output */
-       alc_set_pin_output(codec, nid, pin_type);
-
-       if (dac == 0x25)
-               idx = 4;
-       else if (dac >= 0x02 && dac <= 0x05)
-               idx = dac - 2;
-       else
-               return;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
-}
-
-static void alc882_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i <= HDA_SIDE; i++) {
-               hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               if (nid)
-                       alc882_auto_set_output_and_unmute(codec, nid, pin_type,
-                                       spec->multiout.dac_nids[i]);
-       }
-}
-
-static void alc882_auto_init_hp_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t pin, dac;
-       int i;
-
-       if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) {
-               for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
-                       pin = spec->autocfg.hp_pins[i];
-                       if (!pin)
-                               break;
-                       dac = spec->multiout.hp_nid;
-                       if (!dac)
-                               dac = spec->multiout.dac_nids[0]; /* to front */
-                       alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
-               }
-       }
-
-       if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) {
-               for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
-                       pin = spec->autocfg.speaker_pins[i];
-                       if (!pin)
-                               break;
-                       dac = spec->multiout.extra_out_nid[0];
-                       if (!dac)
-                               dac = spec->multiout.dac_nids[0]; /* to front */
-                       alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
-               }
-       }
-}
-
-static void alc882_auto_init_analog_input(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               alc_set_input_pin(codec, nid, cfg->inputs[i].type);
-               if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_AMP_GAIN_MUTE,
-                                           AMP_OUT_MUTE);
-       }
-}
-
-static void alc882_auto_init_input_src(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int c;
-
-       for (c = 0; c < spec->num_adc_nids; c++) {
-               hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
-               hda_nid_t nid = spec->capsrc_nids[c];
-               unsigned int mux_idx;
-               const struct hda_input_mux *imux;
-               int conns, mute, idx, item;
-
-               /* mute ADC */
-               snd_hda_codec_write(codec, spec->adc_nids[c], 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_IN_MUTE(0));
-
-               conns = snd_hda_get_connections(codec, nid, conn_list,
-                                               ARRAY_SIZE(conn_list));
-               if (conns < 0)
-                       continue;
-               mux_idx = c >= spec->num_mux_defs ? 0 : c;
-               imux = &spec->input_mux[mux_idx];
-               if (!imux->num_items && mux_idx > 0)
-                       imux = &spec->input_mux[0];
-               for (idx = 0; idx < conns; idx++) {
-                       /* if the current connection is the selected one,
-                        * unmute it as default - otherwise mute it
-                        */
-                       mute = AMP_IN_MUTE(idx);
-                       for (item = 0; item < imux->num_items; item++) {
-                               if (imux->items[item].index == idx) {
-                                       if (spec->cur_mux[c] == item)
-                                               mute = AMP_IN_UNMUTE(idx);
-                                       break;
-                               }
-                       }
-                       /* check if we have a selector or mixer
-                        * we could check for the widget type instead, but
-                        * just check for Amp-In presence (in case of mixer
-                        * without amp-in there is something wrong, this
-                        * function shouldn't be used or capsrc nid is wrong)
-                        */
-                       if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
-                               snd_hda_codec_write(codec, nid, 0,
-                                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                                   mute);
-                       else if (mute != AMP_IN_MUTE(idx))
-                               snd_hda_codec_write(codec, nid, 0,
-                                                   AC_VERB_SET_CONNECT_SEL,
-                                                   idx);
-               }
-       }
-}
-
-/* add mic boosts if needed */
-static int alc_auto_add_mic_boost(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i, err;
-       int type_idx = 0;
-       hda_nid_t nid;
-       const char *prev_label = NULL;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               if (cfg->inputs[i].type > AUTO_PIN_MIC)
-                       break;
-               nid = cfg->inputs[i].pin;
-               if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
-                       const char *label;
-                       char boost_label[32];
-
-                       label = hda_get_autocfg_input_label(codec, cfg, i);
-                       if (prev_label && !strcmp(label, prev_label))
-                               type_idx++;
-                       else
-                               type_idx = 0;
-                       prev_label = label;
-
-                       snprintf(boost_label, sizeof(boost_label),
-                                "%s Boost Volume", label);
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         boost_label, type_idx,
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-/* almost identical with ALC880 parser... */
-static int alc882_parse_auto_config(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
-       int err;
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc882_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs)
-               return 0; /* can't find valid BIOS pin config */
-
-       err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_add_multi_channel_mode(codec);
-       if (err < 0)
-               return err;
-       err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
-                                          "Headphone");
-       if (err < 0)
-               return err;
-       err = alc880_auto_create_extra_out(spec,
-                                          spec->autocfg.speaker_pins[0],
-                                          "Speaker");
-       if (err < 0)
-               return err;
-       err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       add_verb(spec, alc883_auto_init_verbs);
-       /* if ADC 0x07 is available, initialize it, too */
-       if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
-               add_verb(spec, alc882_adc1_init_verbs);
-
-       spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux[0];
-
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       return 1; /* config found */
-}
-
-/* additional initialization for auto-configuration model */
-static void alc882_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc882_auto_init_multi_out(codec);
-       alc882_auto_init_hp_out(codec);
-       alc882_auto_init_analog_input(codec);
-       alc882_auto_init_input_src(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
-}
-
-static int patch_alc882(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err, board_config;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       switch (codec->vendor_id) {
-       case 0x10ec0882:
-       case 0x10ec0885:
-               break;
-       default:
-               /* ALC883 and variants */
-               alc_fix_pll_init(codec, 0x20, 0x0a, 10);
-               break;
-       }
-
-       board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
-                                                 alc882_models,
-                                                 alc882_cfg_tbl);
-
-       if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
-               board_config = snd_hda_check_board_codec_sid_config(codec,
-                       ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
-
-       if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = ALC882_AUTO;
-       }
-
-       if (board_config == ALC882_AUTO) {
-               alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
-               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-       }
-
-       alc_auto_parse_customize_define(codec);
-
-       if (board_config == ALC882_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc882_parse_auto_config(codec);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               } else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using base mode...\n");
-                       board_config = ALC882_3ST_DIG;
-               }
-       }
-
-       if (has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               }
-       }
-
-       if (board_config != ALC882_AUTO)
-               setup_preset(codec, &alc882_presets[board_config]);
-
-       spec->stream_analog_playback = &alc882_pcm_analog_playback;
-       spec->stream_analog_capture = &alc882_pcm_analog_capture;
-       /* FIXME: setup DAC5 */
-       /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
-       spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
-
-       spec->stream_digital_playback = &alc882_pcm_digital_playback;
-       spec->stream_digital_capture = &alc882_pcm_digital_capture;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               int i, j;
-               spec->num_adc_nids = 0;
-               for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
-                       const struct hda_input_mux *imux = spec->input_mux;
-                       hda_nid_t cap;
-                       hda_nid_t items[16];
-                       hda_nid_t nid = alc882_adc_nids[i];
-                       unsigned int wcap = get_wcaps(codec, nid);
-                       /* get type */
-                       wcap = get_wcaps_type(wcap);
-                       if (wcap != AC_WID_AUD_IN)
-                               continue;
-                       spec->private_adc_nids[spec->num_adc_nids] = nid;
-                       err = snd_hda_get_connections(codec, nid, &cap, 1);
-                       if (err < 0)
-                               continue;
-                       err = snd_hda_get_connections(codec, cap, items,
-                                                     ARRAY_SIZE(items));
-                       if (err < 0)
-                               continue;
-                       for (j = 0; j < imux->num_items; j++)
-                               if (imux->items[j].index >= err)
-                                       break;
-                       if (j < imux->num_items)
-                               continue;
-                       spec->private_capsrc_nids[spec->num_adc_nids] = cap;
-                       spec->num_adc_nids++;
-               }
-               spec->adc_nids = spec->private_adc_nids;
-               spec->capsrc_nids = spec->private_capsrc_nids;
-       }
-
-       set_capture_mixer(codec);
-
-       if (has_cdefine_beep(codec))
-               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
-       spec->vmaster_nid = 0x0c;
-
-       codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC882_AUTO)
-               spec->init_hook = alc882_auto_init;
-
-       alc_init_jacks(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc882_loopbacks;
-#endif
-
-       return 0;
-}
-
-
-/*
- * ALC262 support
- */
-
-#define ALC262_DIGOUT_NID      ALC880_DIGOUT_NID
-#define ALC262_DIGIN_NID       ALC880_DIGIN_NID
-
-#define alc262_dac_nids                alc260_dac_nids
-#define alc262_adc_nids                alc882_adc_nids
-#define alc262_adc_nids_alt    alc882_adc_nids_alt
-#define alc262_capsrc_nids     alc882_capsrc_nids
-#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
-
-#define alc262_modes           alc260_modes
-#define alc262_capture_source  alc882_capture_source
-
-static const hda_nid_t alc262_dmic_adc_nids[1] = {
-       /* ADC0 */
-       0x09
-};
-
-static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
-
-static const struct snd_kcontrol_new alc262_base_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/* update HP, line and mono-out pins according to the master switch */
-#define alc262_hp_master_update                alc260_hp_master_update
-
-static void alc262_hp_bpc_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x16;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-static void alc262_hp_wildwest_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x16;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-#define alc262_hp_master_sw_get                alc260_hp_master_sw_get
-#define alc262_hp_master_sw_put                alc260_hp_master_sw_put
-
-#define ALC262_HP_MASTER_SWITCH                                        \
-       {                                                       \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
-               .name = "Master Playback Switch",               \
-               .info = snd_ctl_boolean_mono_info,              \
-               .get = alc262_hp_master_sw_get,                 \
-               .put = alc262_hp_master_sw_put,                 \
-       }, \
-       {                                                       \
-               .iface = NID_MAPPING,                           \
-               .name = "Master Playback Switch",               \
-               .private_value = 0x15 | (0x16 << 8) | (0x1b << 16),     \
-       }
-
-
-static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
-       ALC262_HP_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
-                             HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
-                           HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
-       ALC262_HP_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
-                             HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
-                           HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
-       HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       { } /* end */
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hp_t5735_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_hp_t5735_verbs[] = {
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { }
-};
-
-static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_hp_rp5700_verbs[] = {
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
-       {}
-};
-
-static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
-       .num_items = 1,
-       .items = {
-               { "Line", 0x1 },
-       },
-};
-
-/* bind hp and internal speaker mute (with plug check) as master switch */
-#define alc262_hippo_master_update     alc262_hp_master_update
-#define alc262_hippo_master_sw_get     alc262_hp_master_sw_get
-#define alc262_hippo_master_sw_put     alc262_hp_master_sw_put
-
-#define ALC262_HIPPO_MASTER_SWITCH                             \
-       {                                                       \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
-               .name = "Master Playback Switch",               \
-               .info = snd_ctl_boolean_mono_info,              \
-               .get = alc262_hippo_master_sw_get,              \
-               .put = alc262_hippo_master_sw_put,              \
-       },                                                      \
-       {                                                       \
-               .iface = NID_MAPPING,                           \
-               .name = "Master Playback Switch",               \
-               .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
-                            (SUBDEV_SPEAKER(0) << 16), \
-       }
-
-static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hippo_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc262_hippo1_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-
-static const struct snd_kcontrol_new alc262_sony_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_tyan_verbs[] = {
-       /* Headphone automute */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* P11 AUX_IN, white 4-pin connector */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
-       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
-       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
-
-       {}
-};
-
-/* unsolicited event for HP jack sensing */
-static void alc262_tyan_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-
-#define alc262_capture_mixer           alc882_capture_mixer
-#define alc262_capture_alt_mixer       alc882_capture_alt_mixer
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc262_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for
-        * front panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /*
-        * Set up output mixers (0x0c - 0x0e)
-        */
-       /* set vol=0 to output mixers */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-       /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-
-       { }
-};
-
-static const struct hda_verb alc262_eapd_verbs[] = {
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const struct hda_verb alc262_sony_unsol_verbs[] = {
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},   // Front Mic
-
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_toshiba_s06_verbs[] = {
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
-
-static void alc262_toshiba_s06_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x12;
-       spec->int_mic.mux_idx = 9;
-       spec->auto_mic = 1;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-/*
- * nec model
- *  0x15 = headphone
- *  0x16 = internal speaker
- *  0x18 = external mic
- */
-
-static const struct snd_kcontrol_new alc262_nec_mixer[] = {
-       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_nec_verbs[] = {
-       /* Unmute Speaker */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Headphone */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       /* External mic to headphone */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* External mic to speaker */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {}
-};
-
-/*
- * fujitsu model
- *  0x14 = headphone/spdif-out, 0x15 = internal speaker,
- *  0x1b = port replicator headphone out
- */
-
-#define ALC_HP_EVENT   ALC880_HP_EVENT
-
-static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
-       /* Front Mic pin: input vref at 50% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {}
-};
-
-static const struct hda_input_mux alc262_fujitsu_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-               { "CD", 0x4 },
-       },
-};
-
-static const struct hda_input_mux alc262_HP_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-               { "AUX IN", 0x6 },
-       },
-};
-
-static const struct hda_input_mux alc262_HP_D7000_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x2 },
-               { "Line", 0x1 },
-               { "CD", 0x4 },
-       },
-};
-
-static void alc262_fujitsu_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.hp_pins[1] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/* bind volumes of both NID 0x0c and 0x0d */
-static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
-static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc262_hp_master_sw_get,
-               .put = alc262_hp_master_sw_put,
-       },
-       {
-               .iface = NID_MAPPING,
-               .name = "Master Playback Switch",
-               .private_value = 0x1b,
-       },
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static void alc262_lenovo_3000_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc262_hp_master_sw_get,
-               .put = alc262_hp_master_sw_put,
-       },
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-/* additional init verbs for Benq laptops */
-static const struct hda_verb alc262_EAPD_verbs[] = {
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x3070},
-       {}
-};
-
-static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x3050},
-       {}
-};
-
-/* Samsung Q1 Ultra Vista model setup */
-static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_ultra_verbs[] = {
-       /* output mixer */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* speaker */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* HP */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       /* internal mic */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* ADC, choose mic */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
-       {}
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_ultra_automute(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       unsigned int mute;
-
-       mute = 0;
-       /* auto-mute only when HP is used as HP */
-       if (!spec->cur_mux[0]) {
-               spec->jack_present = snd_hda_jack_detect(codec, 0x15);
-               if (spec->jack_present)
-                       mute = HDA_AMP_MUTE;
-       }
-       /* mute/unmute internal speaker */
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, mute);
-       /* mute/unmute HP */
-       snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_ultra_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
-{
-       if ((res >> 26) != ALC880_HP_EVENT)
-               return;
-       alc262_ultra_automute(codec);
-}
-
-static const struct hda_input_mux alc262_ultra_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x1 },
-               { "Headphone", 0x7 },
-       },
-};
-
-static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       int ret;
-
-       ret = alc_mux_enum_put(kcontrol, ucontrol);
-       if (!ret)
-               return 0;
-       /* reprogram the HP pin as mic or HP according to the input source */
-       snd_hda_codec_write_cache(codec, 0x15, 0,
-                                 AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
-       alc262_ultra_automute(codec); /* mute/unmute HP */
-       return ret;
-}
-
-static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = alc_mux_enum_info,
-               .get = alc_mux_enum_get,
-               .put = alc262_ultra_mux_enum_put,
-       },
-       {
-               .iface = NID_MAPPING,
-               .name = "Capture Source",
-               .private_value = 0x15,
-       },
-       { } /* end */
-};
-
-/* We use two mixers depending on the output pin; 0x16 is a mono output
- * and thus it's bound with a different mixer.
- * This function returns which mixer amp should be used.
- */
-static int alc262_check_volbit(hda_nid_t nid)
-{
-       if (!nid)
-               return 0;
-       else if (nid == 0x16)
-               return 2;
-       else
-               return 1;
-}
-
-static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
-                                 const char *pfx, int *vbits, int idx)
-{
-       unsigned long val;
-       int vbit;
-
-       vbit = alc262_check_volbit(nid);
-       if (!vbit)
-               return 0;
-       if (*vbits & vbit) /* a volume control for this mixer already there */
-               return 0;
-       *vbits |= vbit;
-       if (vbit == 2)
-               val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
-       else
-               val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
-       return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
-}
-
-static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
-                                const char *pfx, int idx)
-{
-       unsigned long val;
-
-       if (!nid)
-               return 0;
-       if (nid == 0x16)
-               val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
-       else
-               val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-       return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       const char *pfx;
-       int vbits;
-       int i, err;
-
-       spec->multiout.num_dacs = 1;    /* only use one dac */
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       spec->private_dac_nids[0] = 2;
-
-       pfx = alc_get_line_out_pfx(spec, true);
-       if (!pfx)
-               pfx = "Front";
-       for (i = 0; i < 2; i++) {
-               err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
-               if (err < 0)
-                       return err;
-               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-                       err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
-                                                   "Speaker", i);
-                       if (err < 0)
-                               return err;
-               }
-               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
-                       err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
-                                                   "Headphone", i);
-                       if (err < 0)
-                               return err;
-               }
-       }
-
-       vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
-               alc262_check_volbit(cfg->speaker_pins[0]) |
-               alc262_check_volbit(cfg->hp_pins[0]);
-       if (vbits == 1 || vbits == 2)
-               pfx = "Master"; /* only one mixer is used */
-       vbits = 0;
-       for (i = 0; i < 2; i++) {
-               err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
-                                            &vbits, i);
-               if (err < 0)
-                       return err;
-               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-                       err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
-                                                    "Speaker", &vbits, i);
-                       if (err < 0)
-                               return err;
-               }
-               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
-                       err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
-                                                    "Headphone", &vbits, i);
-                       if (err < 0)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-#define alc262_auto_create_input_ctls \
-       alc882_auto_create_input_ctls
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc262_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for
-        * front panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /*
-        * Set up output mixers (0x0c - 0x0f)
-        */
-       /* set vol=0 to output mixers */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-       /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-
-       { }
-};
-
-static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for
-        * front panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-
-       /*
-        * Set up output mixers (0x0c - 0x0e)
-        */
-       /* set vol=0 to output mixers */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
-       /* Input mixer1: only unmute Mic */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
-       /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
-
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
-       { }
-};
-
-static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for front
-        * panel mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /*
-        * Set up output mixers (0x0c - 0x0e)
-        */
-       /* set vol=0 to output mixers */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },        /* HP */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },       /* Mono */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* rear MIC */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },        /* Line in */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* Front MIC */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },       /* Line out */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },        /* CD in */
-
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-
-       /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
-        /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))},  */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
-        /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
-       /* Input mixer3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
-        /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
-
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
-       { }
-};
-
-static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },       /* Front Speaker */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* MIC jack */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* Front MIC */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
-
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },        /* HP  jack */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
-
-/*
- * Pin config fixes
- */
-enum {
-       PINFIX_FSC_H270,
-       PINFIX_HP_Z200,
-};
-
-static const struct alc_fixup alc262_fixups[] = {
-       [PINFIX_FSC_H270] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x15, 0x0221142f }, /* front HP */
-                       { 0x1b, 0x0121141f }, /* rear HP */
-                       { }
-               }
-       },
-       [PINFIX_HP_Z200] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x16, 0x99130120 }, /* internal speaker */
-                       { }
-               }
-       },
-};
-
-static const struct snd_pci_quirk alc262_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
-       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
-       {}
-};
-
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc262_loopbacks       alc880_loopbacks
-#endif
-
-/* pcm configuration: identical with ALC880 */
-#define alc262_pcm_analog_playback     alc880_pcm_analog_playback
-#define alc262_pcm_analog_capture      alc880_pcm_analog_capture
-#define alc262_pcm_digital_playback    alc880_pcm_digital_playback
-#define alc262_pcm_digital_capture     alc880_pcm_digital_capture
-
-/*
- * BIOS auto configuration
- */
-static int alc262_parse_auto_config(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc262_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs) {
-               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
-                       spec->multiout.max_channels = 2;
-                       spec->no_analog = 1;
-                       goto dig_only;
-               }
-               return 0; /* can't find valid BIOS pin config */
-       }
-       err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- dig_only:
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       add_verb(spec, alc262_volume_init_verbs);
-       spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux[0];
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
-       return 1;
-}
-
-#define alc262_auto_init_multi_out     alc882_auto_init_multi_out
-#define alc262_auto_init_hp_out                alc882_auto_init_hp_out
-#define alc262_auto_init_analog_input  alc882_auto_init_analog_input
-#define alc262_auto_init_input_src     alc882_auto_init_input_src
-
-
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc262_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc262_auto_init_multi_out(codec);
-       alc262_auto_init_hp_out(codec);
-       alc262_auto_init_analog_input(codec);
-       alc262_auto_init_input_src(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
-}
-
-/*
- * configuration and preset
- */
-static const char * const alc262_models[ALC262_MODEL_LAST] = {
-       [ALC262_BASIC]          = "basic",
-       [ALC262_HIPPO]          = "hippo",
-       [ALC262_HIPPO_1]        = "hippo_1",
-       [ALC262_FUJITSU]        = "fujitsu",
-       [ALC262_HP_BPC]         = "hp-bpc",
-       [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
-       [ALC262_HP_TC_T5735]    = "hp-tc-t5735",
-       [ALC262_HP_RP5700]      = "hp-rp5700",
-       [ALC262_BENQ_ED8]       = "benq",
-       [ALC262_BENQ_T31]       = "benq-t31",
-       [ALC262_SONY_ASSAMD]    = "sony-assamd",
-       [ALC262_TOSHIBA_S06]    = "toshiba-s06",
-       [ALC262_TOSHIBA_RX1]    = "toshiba-rx1",
-       [ALC262_ULTRA]          = "ultra",
-       [ALC262_LENOVO_3000]    = "lenovo-3000",
-       [ALC262_NEC]            = "nec",
-       [ALC262_TYAN]           = "tyan",
-       [ALC262_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk alc262_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
-       SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
-       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
-                          ALC262_HP_BPC),
-       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
-                          ALC262_HP_BPC),
-       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
-                          ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200",
-                          ALC262_AUTO),
-       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
-                          ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
-       SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
-       SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
-       SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
-       SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
-       SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
-       SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
-       SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
-       SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
-                     ALC262_HP_TC_T5735),
-       SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
-       SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
-       SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
-       SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
-       SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
-       SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
-#if 0 /* disable the quirk since model=auto works better in recent versions */
-       SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
-                          ALC262_SONY_ASSAMD),
-#endif
-       SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
-                     ALC262_TOSHIBA_RX1),
-       SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
-       SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
-       SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
-       SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
-       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
-                          ALC262_ULTRA),
-       SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
-       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
-       SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
-       SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
-       SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
-       {}
-};
-
-static const struct alc_config_preset alc262_presets[] = {
-       [ALC262_BASIC] = {
-               .mixers = { alc262_base_mixer },
-               .init_verbs = { alc262_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-       },
-       [ALC262_HIPPO] = {
-               .mixers = { alc262_hippo_mixer },
-               .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hippo_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_HIPPO_1] = {
-               .mixers = { alc262_hippo1_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x02,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hippo1_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_FUJITSU] = {
-               .mixers = { alc262_fujitsu_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
-                               alc262_fujitsu_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_fujitsu_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_fujitsu_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_HP_BPC] = {
-               .mixers = { alc262_HP_BPC_mixer },
-               .init_verbs = { alc262_HP_BPC_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_HP_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hp_bpc_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_HP_BPC_D7000_WF] = {
-               .mixers = { alc262_HP_BPC_WildWest_mixer },
-               .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_HP_D7000_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hp_wildwest_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_HP_BPC_D7000_WL] = {
-               .mixers = { alc262_HP_BPC_WildWest_mixer,
-                           alc262_HP_BPC_WildWest_option_mixer },
-               .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_HP_D7000_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hp_wildwest_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_HP_TC_T5735] = {
-               .mixers = { alc262_hp_t5735_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hp_t5735_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_HP_RP5700] = {
-               .mixers = { alc262_hp_rp5700_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_hp_rp5700_capture_source,
-        },
-       [ALC262_BENQ_ED8] = {
-               .mixers = { alc262_base_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-       },
-       [ALC262_SONY_ASSAMD] = {
-               .mixers = { alc262_sony_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x02,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hippo_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_BENQ_T31] = {
-               .mixers = { alc262_benq_t31_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
-                               alc_hp15_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hippo_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_ULTRA] = {
-               .mixers = { alc262_ultra_mixer },
-               .cap_mixer = alc262_ultra_capture_mixer,
-               .init_verbs = { alc262_ultra_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_ultra_capture_source,
-               .adc_nids = alc262_adc_nids, /* ADC0 */
-               .capsrc_nids = alc262_capsrc_nids,
-               .num_adc_nids = 1, /* single ADC */
-               .unsol_event = alc262_ultra_unsol_event,
-               .init_hook = alc262_ultra_automute,
-       },
-       [ALC262_LENOVO_3000] = {
-               .mixers = { alc262_lenovo_3000_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
-                               alc262_lenovo_3000_unsol_verbs,
-                               alc262_lenovo_3000_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_fujitsu_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_lenovo_3000_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_NEC] = {
-               .mixers = { alc262_nec_mixer },
-               .init_verbs = { alc262_nec_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-       },
-       [ALC262_TOSHIBA_S06] = {
-               .mixers = { alc262_toshiba_s06_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
-                                                       alc262_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .capsrc_nids = alc262_dmic_capsrc_nids,
-               .dac_nids = alc262_dac_nids,
-               .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
-               .num_adc_nids = 1, /* single ADC */
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_toshiba_s06_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_TOSHIBA_RX1] = {
-               .mixers = { alc262_toshiba_rx1_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hippo_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_TYAN] = {
-               .mixers = { alc262_tyan_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x02,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_tyan_setup,
-               .init_hook = alc_hp_automute,
-       },
-};
-
-static int patch_alc262(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int board_config;
-       int err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-#if 0
-       /* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
-        * under-run
-        */
-       {
-       int tmp;
-       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
-       tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
-       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
-       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
-       }
-#endif
-       alc_auto_parse_customize_define(codec);
-
-       alc_fix_pll_init(codec, 0x20, 0x0a, 10);
-
-       board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
-                                                 alc262_models,
-                                                 alc262_cfg_tbl);
-
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = ALC262_AUTO;
-       }
-
-       if (board_config == ALC262_AUTO) {
-               alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
-               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-       }
-
-       if (board_config == ALC262_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc262_parse_auto_config(codec);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               } else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using base mode...\n");
-                       board_config = ALC262_BASIC;
-               }
-       }
-
-       if (!spec->no_analog && has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               }
-       }
-
-       if (board_config != ALC262_AUTO)
-               setup_preset(codec, &alc262_presets[board_config]);
-
-       spec->stream_analog_playback = &alc262_pcm_analog_playback;
-       spec->stream_analog_capture = &alc262_pcm_analog_capture;
-
-       spec->stream_digital_playback = &alc262_pcm_digital_playback;
-       spec->stream_digital_capture = &alc262_pcm_digital_capture;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               int i;
-               /* check whether the digital-mic has to be supported */
-               for (i = 0; i < spec->input_mux->num_items; i++) {
-                       if (spec->input_mux->items[i].index >= 9)
-                               break;
-               }
-               if (i < spec->input_mux->num_items) {
-                       /* use only ADC0 */
-                       spec->adc_nids = alc262_dmic_adc_nids;
-                       spec->num_adc_nids = 1;
-                       spec->capsrc_nids = alc262_dmic_capsrc_nids;
-               } else {
-                       /* all analog inputs */
-                       /* check whether NID 0x07 is valid */
-                       unsigned int wcap = get_wcaps(codec, 0x07);
-
-                       /* get type */
-                       wcap = get_wcaps_type(wcap);
-                       if (wcap != AC_WID_AUD_IN) {
-                               spec->adc_nids = alc262_adc_nids_alt;
-                               spec->num_adc_nids =
-                                       ARRAY_SIZE(alc262_adc_nids_alt);
-                               spec->capsrc_nids = alc262_capsrc_nids_alt;
-                       } else {
-                               spec->adc_nids = alc262_adc_nids;
-                               spec->num_adc_nids =
-                                       ARRAY_SIZE(alc262_adc_nids);
-                               spec->capsrc_nids = alc262_capsrc_nids;
-                       }
-               }
-       }
-       if (!spec->cap_mixer && !spec->no_analog)
-               set_capture_mixer(codec);
-       if (!spec->no_analog && has_cdefine_beep(codec))
-               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
-       spec->vmaster_nid = 0x0c;
-
-       codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC262_AUTO)
-               spec->init_hook = alc262_auto_init;
-       spec->shutup = alc_eapd_shutup;
-
-       alc_init_jacks(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc262_loopbacks;
-#endif
-
-       return 0;
-}
-
-/*
- *  ALC268 channel source setting (2 channel)
- */
-#define ALC268_DIGOUT_NID      ALC880_DIGOUT_NID
-#define alc268_modes           alc260_modes
-
-static const hda_nid_t alc268_dac_nids[2] = {
-       /* front, hp */
-       0x02, 0x03
-};
-
-static const hda_nid_t alc268_adc_nids[2] = {
-       /* ADC0-1 */
-       0x08, 0x07
-};
-
-static const hda_nid_t alc268_adc_nids_alt[1] = {
-       /* ADC0 */
-       0x08
-};
-
-static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
-
-static const struct snd_kcontrol_new alc268_base_mixer[] = {
-       /* output mixer control */
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
-       { }
-};
-
-static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
-       /* output mixer control */
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
-       { }
-};
-
-/* bind Beep switches of both NID 0x0f and 0x10 */
-static const struct hda_bind_ctls alc268_bind_beep_sw = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
-               0
-       },
-};
-
-static const struct snd_kcontrol_new alc268_beep_mixer[] = {
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
-       HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
-       { }
-};
-
-static const struct hda_verb alc268_eapd_verbs[] = {
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-/* Toshiba specific */
-static const struct hda_verb alc268_toshiba_verbs[] = {
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
-/* Acer specific */
-/* bind volumes of both NID 0x02 and 0x03 */
-static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
-static void alc268_acer_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-#define alc268_acer_master_sw_get      alc262_hp_master_sw_get
-#define alc268_acer_master_sw_put      alc262_hp_master_sw_put
-
-static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
-       /* output mixer control */
-       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc268_acer_master_sw_get,
-               .put = alc268_acer_master_sw_put,
-       },
-       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
-       { }
-};
-
-static const struct snd_kcontrol_new alc268_acer_mixer[] = {
-       /* output mixer control */
-       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc268_acer_master_sw_get,
-               .put = alc268_acer_master_sw_put,
-       },
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
-       { }
-};
-
-static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
-       /* output mixer control */
-       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc268_acer_master_sw_get,
-               .put = alc268_acer_master_sw_put,
-       },
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
-       { }
-};
-
-static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
-       { }
-};
-
-static const struct hda_verb alc268_acer_verbs[] = {
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { }
-};
-
-/* unsolicited event for HP jack sensing */
-#define alc268_toshiba_setup           alc262_hippo_setup
-
-static void alc268_acer_lc_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x12;
-       spec->int_mic.mux_idx = 6;
-       spec->auto_mic = 1;
-}
-
-static const struct snd_kcontrol_new alc268_dell_mixer[] = {
-       /* output mixer control */
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { }
-};
-
-static const struct hda_verb alc268_dell_verbs[] = {
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
-       { }
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc268_dell_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { }
-};
-
-static const struct hda_verb alc267_quanta_il1_verbs[] = {
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
-       { }
-};
-
-static void alc267_quanta_il1_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc268_base_init_verbs[] = {
-       /* Unmute DAC0-1 and set vol = 0 */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /*
-        * Set up output mixers (0x0c - 0x0e)
-        */
-       /* set vol=0 to output mixers */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-        {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       /* set PCBEEP vol = 0, mute connections */
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-       /* Unmute Selector 23h,24h and set the default input to mic-in */
-
-       {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       { }
-};
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc268_volume_init_verbs[] = {
-       /* set output DAC */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       /* set PCBEEP vol = 0, mute connections */
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-       { }
-};
-
-static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
-       _DEFINE_CAPSRC(1),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc268_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
-       _DEFINE_CAPSRC(2),
-       { } /* end */
-};
-
-static const struct hda_input_mux alc268_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x2 },
-               { "CD", 0x3 },
-       },
-};
-
-static const struct hda_input_mux alc268_acer_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-               { "Line", 0x2 },
-       },
-};
-
-static const struct hda_input_mux alc268_acer_dmic_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x6 },
-               { "Line", 0x2 },
-       },
-};
-
-#ifdef CONFIG_SND_DEBUG
-static const struct snd_kcontrol_new alc268_test_mixer[] = {
-       /* Volume widgets */
-       HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
-       HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
-       HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
-       HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
-       HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
-       HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
-       /* The below appears problematic on some hardwares */
-       /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
-       HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
-
-       /* Modes for retasking pin widgets */
-       ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
-       ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
-       ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
-       ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
-
-       /* Controls for GPIO pins, assuming they are configured as outputs */
-       ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
-       ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
-       ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
-       ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
-
-       /* Switches to allow the digital SPDIF output pin to be enabled.
-        * The ALC268 does not have an SPDIF input.
-        */
-       ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
-
-       /* A switch allowing EAPD to be enabled.  Some laptops seem to use
-        * this output to turn on an external amplifier.
-        */
-       ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
-       ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
-
-       { } /* end */
-};
-#endif
-
-/* create input playback/capture controls for the given pin */
-static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
-                                   const char *ctlname, int idx)
-{
-       hda_nid_t dac;
-       int err;
-
-       switch (nid) {
-       case 0x14:
-       case 0x16:
-               dac = 0x02;
-               break;
-       case 0x15:
-       case 0x1a: /* ALC259/269 only */
-       case 0x1b: /* ALC259/269 only */
-       case 0x21: /* ALC269vb has this pin, too */
-               dac = 0x03;
-               break;
-       default:
-               snd_printd(KERN_WARNING "hda_codec: "
-                          "ignoring pin 0x%x as unknown\n", nid);
-               return 0;
-       }
-       if (spec->multiout.dac_nids[0] != dac &&
-           spec->multiout.dac_nids[1] != dac) {
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
-                                 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
-                                                     HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
-       }
-
-       if (nid != 0x16)
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
-                         HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
-       else /* mono */
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
-                         HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-       return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid;
-       int err;
-
-       spec->multiout.dac_nids = spec->private_dac_nids;
-
-       nid = cfg->line_out_pins[0];
-       if (nid) {
-               const char *name;
-               if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                       name = "Speaker";
-               else
-                       name = "Front";
-               err = alc268_new_analog_output(spec, nid, name, 0);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->speaker_pins[0];
-       if (nid == 0x1d) {
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
-               if (err < 0)
-                       return err;
-       } else if (nid) {
-               err = alc268_new_analog_output(spec, nid, "Speaker", 0);
-               if (err < 0)
-                       return err;
-       }
-       nid = cfg->hp_pins[0];
-       if (nid) {
-               err = alc268_new_analog_output(spec, nid, "Headphone", 0);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
-       if (nid == 0x16) {
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
-                                 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int alc268_auto_create_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
-}
-
-static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type)
-{
-       int idx;
-
-       alc_set_pin_output(codec, nid, pin_type);
-       if (nid == 0x14 || nid == 0x16)
-               idx = 0;
-       else
-               idx = 1;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
-}
-
-static void alc268_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->autocfg.line_outs; i++) {
-               hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               alc268_auto_set_output_and_unmute(codec, nid, pin_type);
-       }
-}
-
-static void alc268_auto_init_hp_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t pin;
-       int i;
-
-       for (i = 0; i < spec->autocfg.hp_outs; i++) {
-               pin = spec->autocfg.hp_pins[i];
-               alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
-       }
-       for (i = 0; i < spec->autocfg.speaker_outs; i++) {
-               pin = spec->autocfg.speaker_pins[i];
-               alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
-       }
-       if (spec->autocfg.mono_out_pin)
-               snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-}
-
-static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
-       hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
-       hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
-       unsigned int    dac_vol1, dac_vol2;
-
-       if (line_nid == 0x1d || speaker_nid == 0x1d) {
-               snd_hda_codec_write(codec, speaker_nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-               /* mute mixer inputs from 0x1d */
-               snd_hda_codec_write(codec, 0x0f, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_IN_UNMUTE(1));
-               snd_hda_codec_write(codec, 0x10, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_IN_UNMUTE(1));
-       } else {
-               /* unmute mixer inputs from 0x1d */
-               snd_hda_codec_write(codec, 0x0f, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
-               snd_hda_codec_write(codec, 0x10, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
-       }
-
-       dac_vol1 = dac_vol2 = 0xb000 | 0x40;    /* set max volume  */
-       if (line_nid == 0x14)
-               dac_vol2 = AMP_OUT_ZERO;
-       else if (line_nid == 0x15)
-               dac_vol1 = AMP_OUT_ZERO;
-       if (hp_nid == 0x14)
-               dac_vol2 = AMP_OUT_ZERO;
-       else if (hp_nid == 0x15)
-               dac_vol1 = AMP_OUT_ZERO;
-       if (line_nid != 0x16 || hp_nid != 0x16 ||
-           spec->autocfg.line_out_pins[1] != 0x16 ||
-           spec->autocfg.line_out_pins[2] != 0x16)
-               dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
-
-       snd_hda_codec_write(codec, 0x02, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
-       snd_hda_codec_write(codec, 0x03, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
-}
-
-/* pcm configuration: identical with ALC880 */
-#define alc268_pcm_analog_playback     alc880_pcm_analog_playback
-#define alc268_pcm_analog_capture      alc880_pcm_analog_capture
-#define alc268_pcm_analog_alt_capture  alc880_pcm_analog_alt_capture
-#define alc268_pcm_digital_playback    alc880_pcm_digital_playback
-
-/*
- * BIOS auto configuration
- */
-static int alc268_parse_auto_config(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc268_ignore[] = { 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc268_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs) {
-               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
-                       spec->multiout.max_channels = 2;
-                       spec->no_analog = 1;
-                       goto dig_only;
-               }
-               return 0; /* can't find valid BIOS pin config */
-       }
-       err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = 2;
-
- dig_only:
-       /* digital only support output */
-       alc_auto_parse_digital(codec);
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
-               add_mixer(spec, alc268_beep_mixer);
-
-       add_verb(spec, alc268_volume_init_verbs);
-       spec->num_mux_defs = 2;
-       spec->input_mux = &spec->private_imux[0];
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
-       return 1;
-}
-
-#define alc268_auto_init_analog_input  alc882_auto_init_analog_input
-#define alc268_auto_init_input_src     alc882_auto_init_input_src
-
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc268_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc268_auto_init_multi_out(codec);
-       alc268_auto_init_hp_out(codec);
-       alc268_auto_init_mono_speaker_out(codec);
-       alc268_auto_init_analog_input(codec);
-       alc268_auto_init_input_src(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
-}
-
-/*
- * configuration and preset
- */
-static const char * const alc268_models[ALC268_MODEL_LAST] = {
-       [ALC267_QUANTA_IL1]     = "quanta-il1",
-       [ALC268_3ST]            = "3stack",
-       [ALC268_TOSHIBA]        = "toshiba",
-       [ALC268_ACER]           = "acer",
-       [ALC268_ACER_DMIC]      = "acer-dmic",
-       [ALC268_ACER_ASPIRE_ONE]        = "acer-aspire",
-       [ALC268_DELL]           = "dell",
-       [ALC268_ZEPTO]          = "zepto",
-#ifdef CONFIG_SND_DEBUG
-       [ALC268_TEST]           = "test",
-#endif
-       [ALC268_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk alc268_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
-       SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
-       SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
-       SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
-       SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
-       SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
-                                               ALC268_ACER_ASPIRE_ONE),
-       SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
-       SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
-       SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
-                       "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
-       /* almost compatible with toshiba but with optional digital outs;
-        * auto-probing seems working fine
-        */
-       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
-                          ALC268_AUTO),
-       SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
-       SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
-       SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
-       SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
-       {}
-};
-
-/* Toshiba laptops have no unique PCI SSID but only codec SSID */
-static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
-       SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
-       SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
-                          ALC268_TOSHIBA),
-       {}
-};
-
-static const struct alc_config_preset alc268_presets[] = {
-       [ALC267_QUANTA_IL1] = {
-               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
-                           alc268_capture_nosrc_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc267_quanta_il1_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc267_quanta_il1_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC268_3ST] = {
-               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
-               .init_verbs = { alc268_base_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-                .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-                .adc_nids = alc268_adc_nids_alt,
-               .capsrc_nids = alc268_capsrc_nids,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC268_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .input_mux = &alc268_capture_source,
-       },
-       [ALC268_TOSHIBA] = {
-               .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc268_toshiba_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
-               .capsrc_nids = alc268_capsrc_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .input_mux = &alc268_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc268_toshiba_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC268_ACER] = {
-               .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc268_acer_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
-               .capsrc_nids = alc268_capsrc_nids,
-               .hp_nid = 0x02,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .input_mux = &alc268_acer_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc268_acer_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC268_ACER_DMIC] = {
-               .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc268_acer_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
-               .capsrc_nids = alc268_capsrc_nids,
-               .hp_nid = 0x02,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .input_mux = &alc268_acer_dmic_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc268_acer_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC268_ACER_ASPIRE_ONE] = {
-               .mixers = { alc268_acer_aspire_one_mixer,
-                           alc268_beep_mixer,
-                           alc268_capture_nosrc_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc268_acer_aspire_one_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
-               .capsrc_nids = alc268_capsrc_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc268_acer_lc_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC268_DELL] = {
-               .mixers = { alc268_dell_mixer, alc268_beep_mixer,
-                           alc268_capture_nosrc_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc268_dell_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
-               .capsrc_nids = alc268_capsrc_nids,
-               .hp_nid = 0x02,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc268_dell_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC268_ZEPTO] = {
-               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc268_toshiba_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
-               .capsrc_nids = alc268_capsrc_nids,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC268_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .input_mux = &alc268_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc268_toshiba_setup,
-               .init_hook = alc_inithook,
-       },
-#ifdef CONFIG_SND_DEBUG
-       [ALC268_TEST] = {
-               .mixers = { alc268_test_mixer, alc268_capture_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc268_volume_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
-               .capsrc_nids = alc268_capsrc_nids,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC268_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .input_mux = &alc268_capture_source,
-       },
-#endif
-};
-
-static int patch_alc268(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int board_config;
-       int i, has_beep, err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
-                                                 alc268_models,
-                                                 alc268_cfg_tbl);
-
-       if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
-               board_config = snd_hda_check_board_codec_sid_config(codec,
-                       ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
-
-       if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = ALC268_AUTO;
-       }
-
-       if (board_config == ALC268_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc268_parse_auto_config(codec);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               } else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using base mode...\n");
-                       board_config = ALC268_3ST;
-               }
-       }
-
-       if (board_config != ALC268_AUTO)
-               setup_preset(codec, &alc268_presets[board_config]);
-
-       spec->stream_analog_playback = &alc268_pcm_analog_playback;
-       spec->stream_analog_capture = &alc268_pcm_analog_capture;
-       spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
-
-       spec->stream_digital_playback = &alc268_pcm_digital_playback;
-
-       has_beep = 0;
-       for (i = 0; i < spec->num_mixers; i++) {
-               if (spec->mixers[i] == alc268_beep_mixer) {
-                       has_beep = 1;
-                       break;
-               }
-       }
-
-       if (has_beep) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               }
-               if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
-                       /* override the amp caps for beep generator */
-                       snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
-                                         (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (0 << AC_AMPCAP_MUTE_SHIFT));
-       }
-
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
-               /* check whether NID 0x07 is valid */
-               unsigned int wcap = get_wcaps(codec, 0x07);
-
-               spec->capsrc_nids = alc268_capsrc_nids;
-               /* get type */
-               wcap = get_wcaps_type(wcap);
-               if (spec->auto_mic ||
-                   wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
-                       spec->adc_nids = alc268_adc_nids_alt;
-                       spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
-                       if (spec->auto_mic)
-                               fixup_automic_adc(codec);
-                       if (spec->auto_mic || spec->input_mux->num_items == 1)
-                               add_mixer(spec, alc268_capture_nosrc_mixer);
-                       else
-                               add_mixer(spec, alc268_capture_alt_mixer);
-               } else {
-                       spec->adc_nids = alc268_adc_nids;
-                       spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
-                       add_mixer(spec, alc268_capture_mixer);
-               }
-       }
-
-       spec->vmaster_nid = 0x02;
-
-       codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC268_AUTO)
-               spec->init_hook = alc268_auto_init;
-       spec->shutup = alc_eapd_shutup;
-
-       alc_init_jacks(codec);
-
-       return 0;
-}
-
-/*
- *  ALC269 channel source setting (2 channel)
- */
-#define ALC269_DIGOUT_NID      ALC880_DIGOUT_NID
-
-#define alc269_dac_nids                alc260_dac_nids
-
-static const hda_nid_t alc269_adc_nids[1] = {
-       /* ADC1 */
-       0x08,
-};
-
-static const hda_nid_t alc269_capsrc_nids[1] = {
-       0x23,
-};
-
-static const hda_nid_t alc269vb_adc_nids[1] = {
-       /* ADC1 */
-       0x09,
-};
-
-static const hda_nid_t alc269vb_capsrc_nids[1] = {
-       0x22,
-};
-
-static const hda_nid_t alc269_adc_candidates[] = {
-       0x08, 0x09, 0x07, 0x11,
-};
-
-#define alc269_modes           alc260_modes
-#define alc269_capture_source  alc880_lg_lw_capture_source
-
-static const struct snd_kcontrol_new alc269_base_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
-       /* output mixer control */
-       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_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 = alc268_acer_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
-       },
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { }
-};
-
-static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
-       /* output mixer control */
-       HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_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 = alc268_acer_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
-       },
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
-       { }
-};
-
-static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc269_asus_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       { } /* end */
-};
-
-/* FSC amilo */
-#define alc269_fujitsu_mixer   alc269_laptop_mixer
-
-static const struct hda_verb alc269_quanta_fl1_verbs[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       { }
-};
-
-static const struct hda_verb alc269_lifebook_verbs[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
-{
-       alc_hp_automute(codec);
-
-       snd_hda_codec_write(codec, 0x20, 0,
-                       AC_VERB_SET_COEF_INDEX, 0x0c);
-       snd_hda_codec_write(codec, 0x20, 0,
-                       AC_VERB_SET_PROC_COEF, 0x680);
-
-       snd_hda_codec_write(codec, 0x20, 0,
-                       AC_VERB_SET_COEF_INDEX, 0x0c);
-       snd_hda_codec_write(codec, 0x20, 0,
-                       AC_VERB_SET_PROC_COEF, 0x480);
-}
-
-#define alc269_lifebook_speaker_automute \
-       alc269_quanta_fl1_speaker_automute
-
-static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
-{
-       unsigned int present_laptop;
-       unsigned int present_dock;
-
-       present_laptop  = snd_hda_jack_detect(codec, 0x18);
-       present_dock    = snd_hda_jack_detect(codec, 0x1b);
-
-       /* Laptop mic port overrides dock mic port, design decision */
-       if (present_dock)
-               snd_hda_codec_write(codec, 0x23, 0,
-                               AC_VERB_SET_CONNECT_SEL, 0x3);
-       if (present_laptop)
-               snd_hda_codec_write(codec, 0x23, 0,
-                               AC_VERB_SET_CONNECT_SEL, 0x0);
-       if (!present_dock && !present_laptop)
-               snd_hda_codec_write(codec, 0x23, 0,
-                               AC_VERB_SET_CONNECT_SEL, 0x1);
-}
-
-static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
-                                   unsigned int res)
-{
-       switch (res >> 26) {
-       case ALC880_HP_EVENT:
-               alc269_quanta_fl1_speaker_automute(codec);
-               break;
-       case ALC880_MIC_EVENT:
-               alc_mic_automute(codec);
-               break;
-       }
-}
-
-static void alc269_lifebook_unsol_event(struct hda_codec *codec,
-                                       unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc269_lifebook_speaker_automute(codec);
-       if ((res >> 26) == ALC880_MIC_EVENT)
-               alc269_lifebook_mic_autoswitch(codec);
-}
-
-static void alc269_quanta_fl1_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-}
-
-static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
-{
-       alc269_quanta_fl1_speaker_automute(codec);
-       alc_mic_automute(codec);
-}
-
-static void alc269_lifebook_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.hp_pins[1] = 0x1a;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-}
-
-static void alc269_lifebook_init_hook(struct hda_codec *codec)
-{
-       alc269_lifebook_speaker_automute(codec);
-       alc269_lifebook_mic_autoswitch(codec);
-}
-
-static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
-
-static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
-
-static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
-
-static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
+enum {
+       ALC_CTL_WIDGET_VOL,
+       ALC_CTL_WIDGET_MUTE,
+       ALC_CTL_BIND_MUTE,
 };
-
-static const struct hda_verb alc271_acer_dmic_verbs[] = {
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x22, AC_VERB_SET_CONNECT_SEL, 6},
-       { }
+static const struct snd_kcontrol_new alc_control_templates[] = {
+       HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+       HDA_CODEC_MUTE(NULL, 0, 0, 0),
+       HDA_BIND_MUTE(NULL, 0, 0, 0),
 };
 
-static void alc269_laptop_amic_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-}
-
-static void alc269_laptop_dmic_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x12;
-       spec->int_mic.mux_idx = 5;
-       spec->auto_mic = 1;
-}
-
-static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x21;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-}
-
-static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
+/* add dynamic controls */
+static int add_control(struct alc_spec *spec, int type, const char *name,
+                      int cidx, unsigned long val)
 {
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x21;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x12;
-       spec->int_mic.mux_idx = 6;
-       spec->auto_mic = 1;
-}
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc269_init_verbs[] = {
-       /*
-        * Unmute ADC0 and set the default input to mic-in
-        */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /*
-        * Set up output mixers (0x02 - 0x03)
-        */
-       /* set vol=0 to output mixers */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* FIXME: use Mux-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* set EAPD */
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-static const struct hda_verb alc269vb_init_verbs[] = {
-       /*
-        * Unmute ADC0 and set the default input to mic-in
-        */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /*
-        * Set up output mixers (0x02 - 0x03)
-        */
-       /* set vol=0 to output mixers */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* FIXME: use Mux-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* set EAPD */
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-#define alc269_auto_create_multi_out_ctls \
-       alc268_auto_create_multi_out_ctls
-#define alc269_auto_create_input_ctls \
-       alc268_auto_create_input_ctls
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc269_loopbacks       alc880_loopbacks
-#endif
-
-/* pcm configuration: identical with ALC880 */
-#define alc269_pcm_analog_playback     alc880_pcm_analog_playback
-#define alc269_pcm_analog_capture      alc880_pcm_analog_capture
-#define alc269_pcm_digital_playback    alc880_pcm_digital_playback
-#define alc269_pcm_digital_capture     alc880_pcm_digital_capture
-
-static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 8,
-       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
-       /* NID is set in alc_build_pcms */
-       .ops = {
-               .open = alc880_playback_pcm_open,
-               .prepare = alc880_playback_pcm_prepare,
-               .cleanup = alc880_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
-       /* NID is set in alc_build_pcms */
-};
+       struct snd_kcontrol_new *knew;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static int alc269_mic2_for_mute_led(struct hda_codec *codec)
-{
-       switch (codec->subsystem_id) {
-       case 0x103c1586:
-               return 1;
-       }
+       knew = alc_kcontrol_new(spec);
+       if (!knew)
+               return -ENOMEM;
+       *knew = alc_control_templates[type];
+       knew->name = kstrdup(name, GFP_KERNEL);
+       if (!knew->name)
+               return -ENOMEM;
+       knew->index = cidx;
+       if (get_amp_nid_(val))
+               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
+       knew->private_value = val;
        return 0;
 }
 
-static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
-{
-       /* update mute-LED according to the speaker mute state */
-       if (nid == 0x01 || nid == 0x14) {
-               int pinval;
-               if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
-                   HDA_AMP_MUTE)
-                       pinval = 0x24;
-               else
-                       pinval = 0x20;
-               /* mic2 vref pin is used for mute LED control */
-               snd_hda_codec_update_cache(codec, 0x19, 0,
-                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                          pinval);
-       }
-       return alc_check_power_status(codec, nid);
-}
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
-
-static int alc275_setup_dual_adc(struct hda_codec *codec)
+static int add_control_with_pfx(struct alc_spec *spec, int type,
+                               const char *pfx, const char *dir,
+                               const char *sfx, int cidx, unsigned long val)
 {
-       struct alc_spec *spec = codec->spec;
-
-       if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
-               return 0;
-       if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
-           (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
-               if (spec->ext_mic.pin <= 0x12) {
-                       spec->private_adc_nids[0] = 0x08;
-                       spec->private_adc_nids[1] = 0x11;
-                       spec->private_capsrc_nids[0] = 0x23;
-                       spec->private_capsrc_nids[1] = 0x22;
-               } else {
-                       spec->private_adc_nids[0] = 0x11;
-                       spec->private_adc_nids[1] = 0x08;
-                       spec->private_capsrc_nids[0] = 0x22;
-                       spec->private_capsrc_nids[1] = 0x23;
-               }
-               spec->adc_nids = spec->private_adc_nids;
-               spec->capsrc_nids = spec->private_capsrc_nids;
-               spec->num_adc_nids = 2;
-               spec->dual_adc_switch = 1;
-               snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
-                           spec->adc_nids[0], spec->adc_nids[1]);
-               return 1;
-       }
-       return 0;
+       char name[32];
+       snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+       return add_control(spec, type, name, cidx, val);
 }
 
-/* different alc269-variants */
-enum {
-       ALC269_TYPE_NORMAL,
-       ALC269_TYPE_ALC258,
-       ALC269_TYPE_ALC259,
-       ALC269_TYPE_ALC269VB,
-       ALC269_TYPE_ALC270,
-       ALC269_TYPE_ALC271X,
-};
+#define add_pb_vol_ctrl(spec, type, pfx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
+#define add_pb_sw_ctrl(spec, type, pfx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
+#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
+#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
 
-/*
- * BIOS auto configuration
- */
-static int alc269_parse_auto_config(struct hda_codec *codec)
+static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
+                                       bool can_be_master, int *index)
 {
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc269_ignore);
-       if (err < 0)
-               return err;
-
-       err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       if (spec->codec_variant == ALC269_TYPE_NORMAL)
-               err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
-       else
-               err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
-                                                0x22, 0);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       alc_auto_parse_digital(codec);
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       static const char * const chname[4] = {
+               "Front", "Surround", NULL /*CLFE*/, "Side"
+       };
 
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
+       *index = 0;
+       if (cfg->line_outs == 1 && !spec->multi_ios &&
+           !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
+               return "Master";
 
-       if (spec->codec_variant != ALC269_TYPE_NORMAL) {
-               add_verb(spec, alc269vb_init_verbs);
-               alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
-       } else {
-               add_verb(spec, alc269_init_verbs);
-               alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
+       switch (cfg->line_out_type) {
+       case AUTO_PIN_SPEAKER_OUT:
+               if (cfg->line_outs == 1)
+                       return "Speaker";
+               break;
+       case AUTO_PIN_HP_OUT:
+               /* for multi-io case, only the primary out */
+               if (ch && spec->multi_ios)
+                       break;
+               *index = ch;
+               return "Headphone";
+       default:
+               if (cfg->line_outs == 1 && !spec->multi_ios)
+                       return "PCM";
+               break;
        }
+       return chname[ch];
+}
 
-       spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux[0];
-
-       if (!alc275_setup_dual_adc(codec))
-               fillup_priv_adc_nids(codec, alc269_adc_candidates,
-                                    sizeof(alc269_adc_candidates));
+/* create input playback/capture controls for the given pin */
+static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
+                           const char *ctlname, int ctlidx,
+                           int idx, hda_nid_t mix_nid)
+{
+       int err;
 
-       err = alc_auto_add_mic_boost(codec);
+       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
+                         HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
-
-       if (!spec->cap_mixer && !spec->no_analog)
-               set_capture_mixer(codec);
-
-       return 1;
-}
-
-#define alc269_auto_init_multi_out     alc268_auto_init_multi_out
-#define alc269_auto_init_hp_out                alc268_auto_init_hp_out
-#define alc269_auto_init_analog_input  alc882_auto_init_analog_input
-#define alc269_auto_init_input_src     alc882_auto_init_input_src
-
-
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc269_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc269_auto_init_multi_out(codec);
-       alc269_auto_init_hp_out(codec);
-       alc269_auto_init_analog_input(codec);
-       if (!spec->dual_adc_switch)
-               alc269_auto_init_input_src(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
+       err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
+                         HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
+       if (err < 0)
+               return err;
+       return 0;
 }
 
-static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
+static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
 {
-       int val = alc_read_coef_idx(codec, 0x04);
-       if (power_up)
-               val |= 1 << 11;
-       else
-               val &= ~(1 << 11);
-       alc_write_coef_idx(codec, 0x04, val);
+       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
+       return (pincap & AC_PINCAP_IN) != 0;
 }
 
-static void alc269_shutup(struct hda_codec *codec)
+/* Parse the codec tree and retrieve ADCs and corresponding capsrc MUXs */
+static int alc_auto_fill_adc_caps(struct hda_codec *codec)
 {
-       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
-               alc269_toggle_power_output(codec, 0);
-       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
-               alc269_toggle_power_output(codec, 0);
-               msleep(150);
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t nid;
+       hda_nid_t *adc_nids = spec->private_adc_nids;
+       hda_nid_t *cap_nids = spec->private_capsrc_nids;
+       int max_nums = ARRAY_SIZE(spec->private_adc_nids);
+       bool indep_capsrc = false;
+       int i, nums = 0;
+
+       nid = codec->start_nid;
+       for (i = 0; i < codec->num_nodes; i++, nid++) {
+               hda_nid_t src;
+               const hda_nid_t *list;
+               unsigned int caps = get_wcaps(codec, nid);
+               int type = get_wcaps_type(caps);
+
+               if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
+                       continue;
+               adc_nids[nums] = nid;
+               cap_nids[nums] = nid;
+               src = nid;
+               for (;;) {
+                       int n;
+                       type = get_wcaps_type(get_wcaps(codec, src));
+                       if (type == AC_WID_PIN)
+                               break;
+                       if (type == AC_WID_AUD_SEL) {
+                               cap_nids[nums] = src;
+                               indep_capsrc = true;
+                               break;
+                       }
+                       n = snd_hda_get_conn_list(codec, src, &list);
+                       if (n > 1) {
+                               cap_nids[nums] = src;
+                               indep_capsrc = true;
+                               break;
+                       } else if (n != 1)
+                               break;
+                       src = *list;
+               }
+               if (++nums >= max_nums)
+                       break;
        }
+       spec->adc_nids = spec->private_adc_nids;
+       spec->capsrc_nids = spec->private_capsrc_nids;
+       spec->num_adc_nids = nums;
+       return nums;
 }
 
-#ifdef SND_HDA_NEEDS_RESUME
-static int alc269_resume(struct hda_codec *codec)
+/* create playback/capture controls for input pins */
+static int alc_auto_create_input_ctls(struct hda_codec *codec)
 {
-       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
-               alc269_toggle_power_output(codec, 0);
-               msleep(150);
-       }
+       struct alc_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t mixer = spec->mixer_nid;
+       struct hda_input_mux *imux = &spec->private_imux[0];
+       int num_adcs;
+       int i, c, err, idx, type_idx = 0;
+       const char *prev_label = NULL;
 
-       codec->patch_ops.init(codec);
+       num_adcs = alc_auto_fill_adc_caps(codec);
+       if (num_adcs < 0)
+               return 0;
 
-       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
-               alc269_toggle_power_output(codec, 1);
-               msleep(200);
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t pin;
+               const char *label;
+
+               pin = cfg->inputs[i].pin;
+               if (!alc_is_input_pin(codec, pin))
+                       continue;
+
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               if (prev_label && !strcmp(label, prev_label))
+                       type_idx++;
+               else
+                       type_idx = 0;
+               prev_label = label;
+
+               if (mixer) {
+                       idx = get_connection_index(codec, mixer, pin);
+                       if (idx >= 0) {
+                               err = new_analog_input(spec, pin,
+                                                      label, type_idx,
+                                                      idx, mixer);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+
+               for (c = 0; c < num_adcs; c++) {
+                       hda_nid_t cap = spec->capsrc_nids ?
+                               spec->capsrc_nids[c] : spec->adc_nids[c];
+                       idx = get_connection_index(codec, cap, pin);
+                       if (idx >= 0) {
+                               spec->imux_pins[imux->num_items] = pin;
+                               snd_hda_add_imux_item(imux, label, idx, NULL);
+                               break;
+                       }
+               }
        }
 
-       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
-               alc269_toggle_power_output(codec, 1);
+       spec->num_mux_defs = 1;
+       spec->input_mux = imux;
 
-       snd_hda_codec_resume_amp(codec);
-       snd_hda_codec_resume_cache(codec);
-       hda_call_check_power_status(codec, 0x01);
        return 0;
 }
-#endif /* SND_HDA_NEEDS_RESUME */
 
-static void alc269_fixup_hweq(struct hda_codec *codec,
-                              const struct alc_fixup *fix, int action)
+static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned int pin_type)
 {
-       int coef;
-
-       if (action != ALC_FIXUP_ACT_INIT)
-               return;
-       coef = alc_read_coef_idx(codec, 0x1e);
-       alc_write_coef_idx(codec, 0x1e, coef | 0x80);
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           pin_type);
+       /* unmute pin */
+       if (nid_has_mute(codec, nid, HDA_OUTPUT))
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           AMP_OUT_UNMUTE);
 }
 
-static void alc271_fixup_dmic(struct hda_codec *codec,
-                             const struct alc_fixup *fix, int action)
+static int get_pin_type(int line_out_type)
 {
-       static const struct hda_verb verbs[] = {
-               {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
-               {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
-               {}
-       };
-       unsigned int cfg;
-
-       if (strcmp(codec->chip_name, "ALC271X"))
-               return;
-       cfg = snd_hda_codec_get_pincfg(codec, 0x12);
-       if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
-               snd_hda_sequence_write(codec, verbs);
+       if (line_out_type == AUTO_PIN_HP_OUT)
+               return PIN_HP;
+       else
+               return PIN_OUT;
 }
 
-enum {
-       ALC269_FIXUP_SONY_VAIO,
-       ALC275_FIXUP_SONY_VAIO_GPIO2,
-       ALC269_FIXUP_DELL_M101Z,
-       ALC269_FIXUP_SKU_IGNORE,
-       ALC269_FIXUP_ASUS_G73JW,
-       ALC269_FIXUP_LENOVO_EAPD,
-       ALC275_FIXUP_SONY_HWEQ,
-       ALC271_FIXUP_DMIC,
-};
-
-static const struct alc_fixup alc269_fixups[] = {
-       [ALC269_FIXUP_SONY_VAIO] = {
-               .type = ALC_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
-                       {}
-               }
-       },
-       [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
-               .type = ALC_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
-                       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
-                       {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_SONY_VAIO
-       },
-       [ALC269_FIXUP_DELL_M101Z] = {
-               .type = ALC_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Enables internal speaker */
-                       {0x20, AC_VERB_SET_COEF_INDEX, 13},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
-                       {}
-               }
-       },
-       [ALC269_FIXUP_SKU_IGNORE] = {
-               .type = ALC_FIXUP_SKU,
-               .v.sku = ALC_FIXUP_SKU_IGNORE,
-       },
-       [ALC269_FIXUP_ASUS_G73JW] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x17, 0x99130111 }, /* subwoofer */
-                       { }
-               }
-       },
-       [ALC269_FIXUP_LENOVO_EAPD] = {
-               .type = ALC_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
-                       {}
-               }
-       },
-       [ALC275_FIXUP_SONY_HWEQ] = {
-               .type = ALC_FIXUP_FUNC,
-               .v.func = alc269_fixup_hweq,
-               .chained = true,
-               .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
-       },
-       [ALC271_FIXUP_DMIC] = {
-               .type = ALC_FIXUP_FUNC,
-               .v.func = alc271_fixup_dmic,
-       },
-};
-
-static const struct snd_pci_quirk alc269_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
-       SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
-       SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
-       SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
-       SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
-       SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
-       SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
-       SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
-       {}
-};
-
-
-/*
- * configuration and preset
- */
-static const char * const alc269_models[ALC269_MODEL_LAST] = {
-       [ALC269_BASIC]                  = "basic",
-       [ALC269_QUANTA_FL1]             = "quanta",
-       [ALC269_AMIC]                   = "laptop-amic",
-       [ALC269_DMIC]                   = "laptop-dmic",
-       [ALC269_FUJITSU]                = "fujitsu",
-       [ALC269_LIFEBOOK]               = "lifebook",
-       [ALC269_AUTO]                   = "auto",
-};
-
-static const struct snd_pci_quirk alc269_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
-       SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
-       SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
-                     ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
-                     ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
-                     ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
-       SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
-       SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
-       SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
-       SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
-       SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
-       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
-       SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
-       SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
-       {}
-};
-
-static const struct alc_config_preset alc269_presets[] = {
-       [ALC269_BASIC] = {
-               .mixers = { alc269_base_mixer },
-               .init_verbs = { alc269_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
-               .dac_nids = alc269_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc269_modes),
-               .channel_mode = alc269_modes,
-               .input_mux = &alc269_capture_source,
-       },
-       [ALC269_QUANTA_FL1] = {
-               .mixers = { alc269_quanta_fl1_mixer },
-               .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
-               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
-               .dac_nids = alc269_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc269_modes),
-               .channel_mode = alc269_modes,
-               .input_mux = &alc269_capture_source,
-               .unsol_event = alc269_quanta_fl1_unsol_event,
-               .setup = alc269_quanta_fl1_setup,
-               .init_hook = alc269_quanta_fl1_init_hook,
-       },
-       [ALC269_AMIC] = {
-               .mixers = { alc269_laptop_mixer },
-               .cap_mixer = alc269_laptop_analog_capture_mixer,
-               .init_verbs = { alc269_init_verbs,
-                               alc269_laptop_amic_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
-               .dac_nids = alc269_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc269_modes),
-               .channel_mode = alc269_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc269_laptop_amic_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC269_DMIC] = {
-               .mixers = { alc269_laptop_mixer },
-               .cap_mixer = alc269_laptop_digital_capture_mixer,
-               .init_verbs = { alc269_init_verbs,
-                               alc269_laptop_dmic_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
-               .dac_nids = alc269_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc269_modes),
-               .channel_mode = alc269_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc269_laptop_dmic_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC269VB_AMIC] = {
-               .mixers = { alc269vb_laptop_mixer },
-               .cap_mixer = alc269vb_laptop_analog_capture_mixer,
-               .init_verbs = { alc269vb_init_verbs,
-                               alc269vb_laptop_amic_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
-               .dac_nids = alc269_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc269_modes),
-               .channel_mode = alc269_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc269vb_laptop_amic_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC269VB_DMIC] = {
-               .mixers = { alc269vb_laptop_mixer },
-               .cap_mixer = alc269vb_laptop_digital_capture_mixer,
-               .init_verbs = { alc269vb_init_verbs,
-                               alc269vb_laptop_dmic_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
-               .dac_nids = alc269_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc269_modes),
-               .channel_mode = alc269_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc269vb_laptop_dmic_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC269_FUJITSU] = {
-               .mixers = { alc269_fujitsu_mixer },
-               .cap_mixer = alc269_laptop_digital_capture_mixer,
-               .init_verbs = { alc269_init_verbs,
-                               alc269_laptop_dmic_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
-               .dac_nids = alc269_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc269_modes),
-               .channel_mode = alc269_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc269_laptop_dmic_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC269_LIFEBOOK] = {
-               .mixers = { alc269_lifebook_mixer },
-               .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
-               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
-               .dac_nids = alc269_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc269_modes),
-               .channel_mode = alc269_modes,
-               .input_mux = &alc269_capture_source,
-               .unsol_event = alc269_lifebook_unsol_event,
-               .setup = alc269_lifebook_setup,
-               .init_hook = alc269_lifebook_init_hook,
-       },
-       [ALC271_ACER] = {
-               .mixers = { alc269_asus_mixer },
-               .cap_mixer = alc269vb_laptop_digital_capture_mixer,
-               .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
-               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
-               .dac_nids = alc269_dac_nids,
-               .adc_nids = alc262_dmic_adc_nids,
-               .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
-               .capsrc_nids = alc262_dmic_capsrc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc269_modes),
-               .channel_mode = alc269_modes,
-               .input_mux = &alc269_capture_source,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc269vb_laptop_dmic_setup,
-               .init_hook = alc_inithook,
-       },
-};
-
-static int alc269_fill_coef(struct hda_codec *codec)
+static void alc_auto_init_analog_input(struct hda_codec *codec)
 {
-       int val;
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
 
-       if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
-               alc_write_coef_idx(codec, 0xf, 0x960b);
-               alc_write_coef_idx(codec, 0xe, 0x8817);
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               if (alc_is_input_pin(codec, nid)) {
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
+                       if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+                               snd_hda_codec_write(codec, nid, 0,
+                                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                                   AMP_OUT_MUTE);
+               }
        }
 
-       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
-               alc_write_coef_idx(codec, 0xf, 0x960b);
-               alc_write_coef_idx(codec, 0xe, 0x8814);
+       /* mute all loopback inputs */
+       if (spec->mixer_nid) {
+               int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
+               for (i = 0; i < nums; i++)
+                       snd_hda_codec_write(codec, spec->mixer_nid, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_IN_MUTE(i));
        }
+}
 
-       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
-               val = alc_read_coef_idx(codec, 0x04);
-               /* Power up output pin */
-               alc_write_coef_idx(codec, 0x04, val | (1<<11));
-       }
+/* convert from MIX nid to DAC */
+static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
+{
+       hda_nid_t list[5];
+       int i, num;
 
-       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
-               val = alc_read_coef_idx(codec, 0xd);
-               if ((val & 0x0c00) >> 10 != 0x1) {
-                       /* Capless ramp up clock control */
-                       alc_write_coef_idx(codec, 0xd, val | (1<<10));
-               }
-               val = alc_read_coef_idx(codec, 0x17);
-               if ((val & 0x01c0) >> 6 != 0x4) {
-                       /* Class D power on reset */
-                       alc_write_coef_idx(codec, 0x17, val | (1<<7));
-               }
+       if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT)
+               return nid;
+       num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
+       for (i = 0; i < num; i++) {
+               if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
+                       return list[i];
        }
+       return 0;
+}
 
-       val = alc_read_coef_idx(codec, 0xd); /* Class D */
-       alc_write_coef_idx(codec, 0xd, val | (1<<14));
+/* go down to the selector widget before the mixer */
+static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
+{
+       hda_nid_t srcs[5];
+       int num = snd_hda_get_connections(codec, pin, srcs,
+                                         ARRAY_SIZE(srcs));
+       if (num != 1 ||
+           get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
+               return pin;
+       return srcs[0];
+}
 
-       val = alc_read_coef_idx(codec, 0x4); /* HP */
-       alc_write_coef_idx(codec, 0x4, val | (1<<11));
+/* get MIX nid connected to the given pin targeted to DAC */
+static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
+                                  hda_nid_t dac)
+{
+       hda_nid_t mix[5];
+       int i, num;
 
+       pin = alc_go_down_to_selector(codec, pin);
+       num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
+       for (i = 0; i < num; i++) {
+               if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
+                       return mix[i];
+       }
        return 0;
 }
 
-static int patch_alc269(struct hda_codec *codec)
+/* select the connection from pin to DAC if needed */
+static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
+                              hda_nid_t dac)
 {
-       struct alc_spec *spec;
-       int board_config, coef;
-       int err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
+       hda_nid_t mix[5];
+       int i, num;
 
-       codec->spec = spec;
+       pin = alc_go_down_to_selector(codec, pin);
+       num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
+       if (num < 2)
+               return 0;
+       for (i = 0; i < num; i++) {
+               if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
+                       snd_hda_codec_update_cache(codec, pin, 0,
+                                                  AC_VERB_SET_CONNECT_SEL, i);
+                       return 0;
+               }
+       }
+       return 0;
+}
 
-       alc_auto_parse_customize_define(codec);
+/* look for an empty DAC slot */
+static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t srcs[5];
+       int i, num;
 
-       if (codec->vendor_id == 0x10ec0269) {
-               coef = alc_read_coef_idx(codec, 0);
-               if ((coef & 0x00f0) == 0x0010) {
-                       if (codec->bus->pci->subsystem_vendor == 0x1025 &&
-                           spec->cdefine.platform_type == 1) {
-                               alc_codec_rename(codec, "ALC271X");
-                               spec->codec_variant = ALC269_TYPE_ALC271X;
-                       } else if ((coef & 0xf000) == 0x1000) {
-                               spec->codec_variant = ALC269_TYPE_ALC270;
-                       } else if ((coef & 0xf000) == 0x2000) {
-                               alc_codec_rename(codec, "ALC259");
-                               spec->codec_variant = ALC269_TYPE_ALC259;
-                       } else if ((coef & 0xf000) == 0x3000) {
-                               alc_codec_rename(codec, "ALC258");
-                               spec->codec_variant = ALC269_TYPE_ALC258;
-                       } else {
-                               alc_codec_rename(codec, "ALC269VB");
-                               spec->codec_variant = ALC269_TYPE_ALC269VB;
-                       }
-               } else
-                       alc_fix_pll_init(codec, 0x20, 0x04, 15);
-               alc269_fill_coef(codec);
+       pin = alc_go_down_to_selector(codec, pin);
+       num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
+       for (i = 0; i < num; i++) {
+               hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
+               if (!nid)
+                       continue;
+               if (found_in_nid_list(nid, spec->multiout.dac_nids,
+                                     spec->multiout.num_dacs))
+                       continue;
+               if (spec->multiout.hp_nid == nid)
+                       continue;
+               if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
+                                     ARRAY_SIZE(spec->multiout.extra_out_nid)))
+                   continue;
+               return nid;
        }
+       return 0;
+}
 
-       board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
-                                                 alc269_models,
-                                                 alc269_cfg_tbl);
+static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
+{
+       hda_nid_t sel = alc_go_down_to_selector(codec, pin);
+       if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
+               return alc_auto_look_for_dac(codec, pin);
+       return 0;
+}
 
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = ALC269_AUTO;
-       }
+/* fill in the dac_nids table from the parsed pin configuration */
+static int alc_auto_fill_dac_nids(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       bool redone = false;
+       int i;
 
-       if (board_config == ALC269_AUTO) {
-               alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
-               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-       }
+ again:
+       spec->multiout.num_dacs = 0;
+       spec->multiout.hp_nid = 0;
+       spec->multiout.extra_out_nid[0] = 0;
+       memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
+       spec->multiout.dac_nids = spec->private_dac_nids;
 
-       if (board_config == ALC269_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc269_parse_auto_config(codec);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               } else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using base mode...\n");
-                       board_config = ALC269_BASIC;
-               }
+       /* fill hard-wired DACs first */
+       if (!redone) {
+               for (i = 0; i < cfg->line_outs; i++)
+                       spec->private_dac_nids[i] =
+                               get_dac_if_single(codec, cfg->line_out_pins[i]);
+               if (cfg->hp_outs)
+                       spec->multiout.hp_nid =
+                               get_dac_if_single(codec, cfg->hp_pins[0]);
+               if (cfg->speaker_outs)
+                       spec->multiout.extra_out_nid[0] =
+                               get_dac_if_single(codec, cfg->speaker_pins[0]);
        }
 
-       if (has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
+       for (i = 0; i < cfg->line_outs; i++) {
+               hda_nid_t pin = cfg->line_out_pins[i];
+               if (spec->private_dac_nids[i])
+                       continue;
+               spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
+               if (!spec->private_dac_nids[i] && !redone) {
+                       /* if we can't find primary DACs, re-probe without
+                        * checking the hard-wired DACs
+                        */
+                       redone = true;
+                       goto again;
                }
        }
 
-       if (board_config != ALC269_AUTO)
-               setup_preset(codec, &alc269_presets[board_config]);
-
-       if (board_config == ALC269_QUANTA_FL1) {
-               /* Due to a hardware problem on Lenovo Ideadpad, we need to
-                * fix the sample rate of analog I/O to 44.1kHz
-                */
-               spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
-               spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
-       } else if (spec->dual_adc_switch) {
-               spec->stream_analog_playback = &alc269_pcm_analog_playback;
-               /* switch ADC dynamically */
-               spec->stream_analog_capture = &dualmic_pcm_analog_capture;
-       } else {
-               spec->stream_analog_playback = &alc269_pcm_analog_playback;
-               spec->stream_analog_capture = &alc269_pcm_analog_capture;
-       }
-       spec->stream_digital_playback = &alc269_pcm_digital_playback;
-       spec->stream_digital_capture = &alc269_pcm_digital_capture;
-
-       if (!spec->adc_nids) { /* wasn't filled automatically? use default */
-               if (spec->codec_variant == ALC269_TYPE_NORMAL) {
-                       spec->adc_nids = alc269_adc_nids;
-                       spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
-                       spec->capsrc_nids = alc269_capsrc_nids;
-               } else {
-                       spec->adc_nids = alc269vb_adc_nids;
-                       spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
-                       spec->capsrc_nids = alc269vb_capsrc_nids;
-               }
+       for (i = 0; i < cfg->line_outs; i++) {
+               if (spec->private_dac_nids[i])
+                       spec->multiout.num_dacs++;
+               else
+                       memmove(spec->private_dac_nids + i,
+                               spec->private_dac_nids + i + 1,
+                               sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
        }
 
-       if (!spec->cap_mixer)
-               set_capture_mixer(codec);
-       if (has_cdefine_beep(codec))
-               set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
-
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
-       spec->vmaster_nid = 0x02;
-
-       codec->patch_ops = alc_patch_ops;
-#ifdef SND_HDA_NEEDS_RESUME
-       codec->patch_ops.resume = alc269_resume;
-#endif
-       if (board_config == ALC269_AUTO)
-               spec->init_hook = alc269_auto_init;
-       spec->shutup = alc269_shutup;
-
-       alc_init_jacks(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc269_loopbacks;
-       if (alc269_mic2_for_mute_led(codec))
-               codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
-#endif
+       if (cfg->hp_outs && !spec->multiout.hp_nid)
+               spec->multiout.hp_nid =
+                       alc_auto_look_for_dac(codec, cfg->hp_pins[0]);
+       if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0])
+               spec->multiout.extra_out_nid[0] =
+                       alc_auto_look_for_dac(codec, cfg->speaker_pins[0]);
 
        return 0;
 }
 
-/*
- *  ALC861 channel source setting (2/6 channel selection for 3-stack)
- */
+static int alc_auto_add_vol_ctl(struct hda_codec *codec,
+                             const char *pfx, int cidx,
+                             hda_nid_t nid, unsigned int chs)
+{
+       if (!nid)
+               return 0;
+       return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
+                                HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+}
 
-/*
- * set the path ways for 2 channel output
- * need to set the codec line out and mic 1 pin widgets to inputs
- */
-static const struct hda_verb alc861_threestack_ch2_init[] = {
-       /* set pin widget 1Ah (line in) for input */
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* set pin widget 18h (mic1/2) for input, for mic also enable
-        * the vref
-        */
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
+       alc_auto_add_vol_ctl(codec, pfx, cidx, nid, 3)
 
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
-#if 0
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
-#endif
-       { } /* end */
-};
-/*
- * 6ch mode
- * need to set the codec line out and mic 1 pin widgets to outputs
+/* create a mute-switch for the given mixer widget;
+ * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
  */
-static const struct hda_verb alc861_threestack_ch6_init[] = {
-       /* set pin widget 1Ah (line in) for output (Back Surround)*/
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* set pin widget 18h (mic1) for output (CLFE)*/
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-
-       { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
-
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
-#if 0
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
-#endif
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc861_threestack_modes[2] = {
-       { 2, alc861_threestack_ch2_init },
-       { 6, alc861_threestack_ch6_init },
-};
-/* Set mic1 as input and unmute the mixer */
-static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
-       { } /* end */
-};
-/* Set mic1 as output and mute mixer */
-static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
-       { 2, alc861_uniwill_m31_ch2_init },
-       { 4, alc861_uniwill_m31_ch4_init },
-};
+static int alc_auto_add_sw_ctl(struct hda_codec *codec,
+                            const char *pfx, int cidx,
+                            hda_nid_t nid, unsigned int chs)
+{
+       int wid_type;
+       int type;
+       unsigned long val;
+       if (!nid)
+               return 0;
+       wid_type = get_wcaps_type(get_wcaps(codec, nid));
+       if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
+               type = ALC_CTL_WIDGET_MUTE;
+               val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
+       } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
+               type = ALC_CTL_WIDGET_MUTE;
+               val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
+       } else {
+               type = ALC_CTL_BIND_MUTE;
+               val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
+       }
+       return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
+}
 
-/* Set mic1 and line-in as input and unmute the mixer */
-static const struct hda_verb alc861_asus_ch2_init[] = {
-       /* set pin widget 1Ah (line in) for input */
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* set pin widget 18h (mic1/2) for input, for mic also enable
-        * the vref
-        */
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+#define alc_auto_add_stereo_sw(codec, pfx, cidx, nid)  \
+       alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3)
 
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
-#if 0
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
-#endif
-       { } /* end */
-};
-/* Set mic1 nad line-in as output and mute mixer */
-static const struct hda_verb alc861_asus_ch6_init[] = {
-       /* set pin widget 1Ah (line in) for output (Back Surround)*/
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
-       /* set pin widget 18h (mic1) for output (CLFE)*/
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
-       { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
-
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
-#if 0
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
-#endif
-       { } /* end */
-};
+static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
+                                          hda_nid_t pin, hda_nid_t dac)
+{
+       hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
+       if (nid_has_mute(codec, pin, HDA_OUTPUT))
+               return pin;
+       else if (mix && nid_has_mute(codec, mix, HDA_INPUT))
+               return mix;
+       else if (nid_has_mute(codec, dac, HDA_OUTPUT))
+               return dac;
+       return 0;
+}
 
-static const struct hda_channel_mode alc861_asus_modes[2] = {
-       { 2, alc861_asus_ch2_init },
-       { 6, alc861_asus_ch6_init },
-};
+static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
+                                         hda_nid_t pin, hda_nid_t dac)
+{
+       hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
+       if (nid_has_volume(codec, dac, HDA_OUTPUT))
+               return dac;
+       else if (nid_has_volume(codec, mix, HDA_OUTPUT))
+               return mix;
+       else if (nid_has_volume(codec, pin, HDA_OUTPUT))
+               return pin;
+       return 0;
+}
 
-/* patch-ALC861 */
-
-static const struct snd_kcontrol_new alc861_base_mixer[] = {
-        /* output mixer control */
-       HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
-
-        /*Input mixer control */
-       /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-          HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
+/* add playback controls from the parsed DAC table */
+static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       struct alc_spec *spec = codec->spec;
+       int i, err, noutputs;
 
-       { } /* end */
-};
+       noutputs = cfg->line_outs;
+       if (spec->multi_ios > 0)
+               noutputs += spec->multi_ios;
 
-static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
-        /* output mixer control */
-       HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
-       /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
-
-       /* Input mixer control */
-       /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-          HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
+       for (i = 0; i < noutputs; i++) {
+               const char *name;
+               int index;
+               hda_nid_t dac, pin;
+               hda_nid_t sw, vol;
 
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-                .private_value = ARRAY_SIZE(alc861_threestack_modes),
-       },
-       { } /* end */
-};
+               dac = spec->multiout.dac_nids[i];
+               if (!dac)
+                       continue;
+               if (i >= cfg->line_outs)
+                       pin = spec->multi_io[i - 1].pin;
+               else
+                       pin = cfg->line_out_pins[i];
 
-static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
-        /* output mixer control */
-       HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+               sw = alc_look_for_out_mute_nid(codec, pin, dac);
+               vol = alc_look_for_out_vol_nid(codec, pin, dac);
+               name = alc_get_line_out_pfx(spec, i, true, &index);
+               if (!name) {
+                       /* Center/LFE */
+                       err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1);
+                       if (err < 0)
+                               return err;
+                       err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2);
+                       if (err < 0)
+                               return err;
+                       err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1);
+                       if (err < 0)
+                               return err;
+                       err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2);
+                       if (err < 0)
+                               return err;
+               } else {
+                       err = alc_auto_add_stereo_vol(codec, name, index, vol);
+                       if (err < 0)
+                               return err;
+                       err = alc_auto_add_stereo_sw(codec, name, index, sw);
+                       if (err < 0)
+                               return err;
+               }
+       }
+       return 0;
+}
 
-       { } /* end */
-};
+/* add playback controls for speaker and HP outputs */
+static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
+                                       hda_nid_t dac, const char *pfx)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t sw, vol;
+       int err;
 
-static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
-        /* output mixer control */
-       HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
-       /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
-
-       /* Input mixer control */
-       /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-          HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
+       if (!pin)
+               return 0;
+       if (!dac) {
+               /* the corresponding DAC is already occupied */
+               if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
+                       return 0; /* no way */
+               /* create a switch only */
+               return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
+                                  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       }
 
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-                .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
-       },
-       { } /* end */
-};
+       sw = alc_look_for_out_mute_nid(codec, pin, dac);
+       vol = alc_look_for_out_vol_nid(codec, pin, dac);
+       err = alc_auto_add_stereo_vol(codec, pfx, 0, vol);
+       if (err < 0)
+               return err;
+       err = alc_auto_add_stereo_sw(codec, pfx, 0, sw);
+       if (err < 0)
+               return err;
+       return 0;
+}
 
-static const struct snd_kcontrol_new alc861_asus_mixer[] = {
-        /* output mixer control */
-       HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
-
-       /* Input mixer control */
-       HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
+static int alc_auto_create_hp_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       return alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
+                                        spec->multiout.hp_nid,
+                                        "Headphone");
+}
 
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-                .private_value = ARRAY_SIZE(alc861_asus_modes),
-       },
-       { }
-};
+static int alc_auto_create_speaker_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       return alc_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0],
+                                        spec->multiout.extra_out_nid[0],
+                                        "Speaker");
+}
 
-/* additional mixer */
-static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
-       { }
-};
+static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
+                                             hda_nid_t pin, int pin_type,
+                                             hda_nid_t dac)
+{
+       int i, num;
+       hda_nid_t nid, mix = 0;
+       hda_nid_t srcs[HDA_MAX_CONNECTIONS];
 
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc861_base_init_verbs[] = {
-       /*
-        * Unmute ADC0 and set the default input to mic-in
-        */
-       /* port-A for surround (rear panel) */
-       { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-B for mic-in (rear panel) with vref */
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* port-C for line-in (rear panel) */
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* port-D for Front */
-       { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-E for HP out (front panel) */
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-       /* route front PCM to HP */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-F for mic-in (front panel) with vref */
-       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* port-G for CLFE (rear panel) */
-       { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-H for side (rear panel) */
-       { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* CD-in */
-       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* route front mic to ADC1*/
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Unmute DAC0~3 & spdif out*/
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Unmute Mixer 14 (mic) 1c (Line in)*/
-       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* Unmute Stereo Mixer 15 */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
-
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* hp used DAC 3 (Front) */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       alc_set_pin_output(codec, pin, pin_type);
+       nid = alc_go_down_to_selector(codec, pin);
+       num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
+       for (i = 0; i < num; i++) {
+               if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
+                       continue;
+               mix = srcs[i];
+               break;
+       }
+       if (!mix)
+               return;
 
-       { }
-};
+       /* need the manual connection? */
+       if (num > 1)
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
+       /* unmute mixer widget inputs */
+       if (nid_has_mute(codec, mix, HDA_INPUT)) {
+               snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           AMP_IN_UNMUTE(0));
+               snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           AMP_IN_UNMUTE(1));
+       }
+       /* initialize volume */
+       nid = alc_look_for_out_vol_nid(codec, pin, dac);
+       if (nid)
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_OUT_ZERO);
+}
 
-static const struct hda_verb alc861_threestack_init_verbs[] = {
-       /*
-        * Unmute ADC0 and set the default input to mic-in
-        */
-       /* port-A for surround (rear panel) */
-       { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       /* port-B for mic-in (rear panel) with vref */
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* port-C for line-in (rear panel) */
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* port-D for Front */
-       { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-E for HP out (front panel) */
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-       /* route front PCM to HP */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-F for mic-in (front panel) with vref */
-       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* port-G for CLFE (rear panel) */
-       { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       /* port-H for side (rear panel) */
-       { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       /* CD-in */
-       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* route front mic to ADC1*/
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Unmute DAC0~3 & spdif out*/
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Unmute Mixer 14 (mic) 1c (Line in)*/
-       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* Unmute Stereo Mixer 15 */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
-
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* hp used DAC 3 (Front) */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       { }
-};
+static void alc_auto_init_multi_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int pin_type = get_pin_type(spec->autocfg.line_out_type);
+       int i;
 
-static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
-       /*
-        * Unmute ADC0 and set the default input to mic-in
-        */
-       /* port-A for surround (rear panel) */
-       { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       /* port-B for mic-in (rear panel) with vref */
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* port-C for line-in (rear panel) */
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* port-D for Front */
-       { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-E for HP out (front panel) */
-       /* this has to be set to VREF80 */
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* route front PCM to HP */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-F for mic-in (front panel) with vref */
-       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* port-G for CLFE (rear panel) */
-       { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       /* port-H for side (rear panel) */
-       { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       /* CD-in */
-       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* route front mic to ADC1*/
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Unmute DAC0~3 & spdif out*/
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Unmute Mixer 14 (mic) 1c (Line in)*/
-       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* Unmute Stereo Mixer 15 */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
-
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* hp used DAC 3 (Front) */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       { }
-};
+       for (i = 0; i <= HDA_SIDE; i++) {
+               hda_nid_t nid = spec->autocfg.line_out_pins[i];
+               if (nid)
+                       alc_auto_set_output_and_unmute(codec, nid, pin_type,
+                                       spec->multiout.dac_nids[i]);
+       }
+}
 
-static const struct hda_verb alc861_asus_init_verbs[] = {
-       /*
-        * Unmute ADC0 and set the default input to mic-in
-        */
-       /* port-A for surround (rear panel)
-        * according to codec#0 this is the HP jack
-        */
-       { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
-       /* route front PCM to HP */
-       { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       /* port-B for mic-in (rear panel) with vref */
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* port-C for line-in (rear panel) */
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* port-D for Front */
-       { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-E for HP out (front panel) */
-       /* this has to be set to VREF80 */
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* route front PCM to HP */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       /* port-F for mic-in (front panel) with vref */
-       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* port-G for CLFE (rear panel) */
-       { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* port-H for side (rear panel) */
-       { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* CD-in */
-       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* route front mic to ADC1*/
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Unmute DAC0~3 & spdif out*/
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Unmute Mixer 14 (mic) 1c (Line in)*/
-       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* Unmute Stereo Mixer 15 */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
-
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* hp used DAC 3 (Front) */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       { }
-};
+static void alc_auto_init_extra_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t pin;
 
-/* additional init verbs for ASUS laptops */
-static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
-       { }
-};
+       pin = spec->autocfg.hp_pins[0];
+       if (pin)
+               alc_auto_set_output_and_unmute(codec, pin, PIN_HP,
+                                                 spec->multiout.hp_nid);
+       pin = spec->autocfg.speaker_pins[0];
+       if (pin)
+               alc_auto_set_output_and_unmute(codec, pin, PIN_OUT,
+                                       spec->multiout.extra_out_nid[0]);
+}
 
 /*
- * generic initialization of ADC, input mixers and output mixers
+ * multi-io helper
  */
-static const struct hda_verb alc861_auto_init_verbs[] = {
-       /*
-        * Unmute ADC0 and set the default input to mic-in
-        */
-       /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Unmute DAC0~3 & spdif out*/
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Unmute Mixer 14 (mic) 1c (Line in)*/
-       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* Unmute Stereo Mixer 15 */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
-
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},  /* set Mic 1 */
-
-       { }
-};
-
-static const struct hda_verb alc861_toshiba_init_verbs[] = {
-       {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+static int alc_auto_fill_multi_ios(struct hda_codec *codec,
+                                  unsigned int location)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int type, i, num_pins = 0;
 
-       { }
-};
+       for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
+               for (i = 0; i < cfg->num_inputs; i++) {
+                       hda_nid_t nid = cfg->inputs[i].pin;
+                       hda_nid_t dac;
+                       unsigned int defcfg, caps;
+                       if (cfg->inputs[i].type != type)
+                               continue;
+                       defcfg = snd_hda_codec_get_pincfg(codec, nid);
+                       if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
+                               continue;
+                       if (location && get_defcfg_location(defcfg) != location)
+                               continue;
+                       caps = snd_hda_query_pin_caps(codec, nid);
+                       if (!(caps & AC_PINCAP_OUT))
+                               continue;
+                       dac = alc_auto_look_for_dac(codec, nid);
+                       if (!dac)
+                               continue;
+                       spec->multi_io[num_pins].pin = nid;
+                       spec->multi_io[num_pins].dac = dac;
+                       num_pins++;
+                       spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+               }
+       }
+       spec->multiout.num_dacs = 1;
+       if (num_pins < 2)
+               return 0;
+       return num_pins;
+}
 
-/* toggle speaker-output according to the hp-jack state */
-static void alc861_toshiba_automute(struct hda_codec *codec)
+static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
 {
-       unsigned int present = snd_hda_jack_detect(codec, 0x0f);
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
 
-       snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
-                                HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = spec->multi_ios + 1;
+       if (uinfo->value.enumerated.item > spec->multi_ios)
+               uinfo->value.enumerated.item = spec->multi_ios;
+       sprintf(uinfo->value.enumerated.name, "%dch",
+               (uinfo->value.enumerated.item + 1) * 2);
+       return 0;
 }
 
-static void alc861_toshiba_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
+static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc861_toshiba_automute(codec);
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
+       return 0;
 }
 
-/* pcm configuration: identical with ALC880 */
-#define alc861_pcm_analog_playback     alc880_pcm_analog_playback
-#define alc861_pcm_analog_capture      alc880_pcm_analog_capture
-#define alc861_pcm_digital_playback    alc880_pcm_digital_playback
-#define alc861_pcm_digital_capture     alc880_pcm_digital_capture
+static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t nid = spec->multi_io[idx].pin;
+
+       if (!spec->multi_io[idx].ctl_in)
+               spec->multi_io[idx].ctl_in =
+                       snd_hda_codec_read(codec, nid, 0,
+                                          AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+       if (output) {
+               snd_hda_codec_update_cache(codec, nid, 0,
+                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                          PIN_OUT);
+               if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+                                                HDA_AMP_MUTE, 0);
+               alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
+       } else {
+               if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+                                                HDA_AMP_MUTE, HDA_AMP_MUTE);
+               snd_hda_codec_update_cache(codec, nid, 0,
+                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                          spec->multi_io[idx].ctl_in);
+       }
+       return 0;
+}
 
+static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       int i, ch;
 
-#define ALC861_DIGOUT_NID      0x07
+       ch = ucontrol->value.enumerated.item[0];
+       if (ch < 0 || ch > spec->multi_ios)
+               return -EINVAL;
+       if (ch == (spec->ext_channel_count - 1) / 2)
+               return 0;
+       spec->ext_channel_count = (ch + 1) * 2;
+       for (i = 0; i < spec->multi_ios; i++)
+               alc_set_multi_io(codec, i, i < ch);
+       spec->multiout.max_channels = spec->ext_channel_count;
+       if (spec->need_dac_fix && !spec->const_channel_count)
+               spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+       return 1;
+}
 
-static const struct hda_channel_mode alc861_8ch_modes[1] = {
-       { 8, NULL }
+static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Channel Mode",
+       .info = alc_auto_ch_mode_info,
+       .get = alc_auto_ch_mode_get,
+       .put = alc_auto_ch_mode_put,
 };
 
-static const hda_nid_t alc861_dac_nids[4] = {
-       /* front, surround, clfe, side */
-       0x03, 0x06, 0x05, 0x04
-};
+static int alc_auto_add_multi_channel_mode(struct hda_codec *codec,
+                                          int (*fill_dac)(struct hda_codec *))
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int location, defcfg;
+       int num_pins;
 
-static const hda_nid_t alc660_dac_nids[3] = {
-       /* front, clfe, surround */
-       0x03, 0x05, 0x06
-};
+       if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs == 1) {
+               /* use HP as primary out */
+               cfg->speaker_outs = cfg->line_outs;
+               memcpy(cfg->speaker_pins, cfg->line_out_pins,
+                      sizeof(cfg->speaker_pins));
+               cfg->line_outs = cfg->hp_outs;
+               memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
+               cfg->hp_outs = 0;
+               memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+               cfg->line_out_type = AUTO_PIN_HP_OUT;
+               if (fill_dac)
+                       fill_dac(codec);
+       }
+       if (cfg->line_outs != 1 ||
+           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+               return 0;
 
-static const hda_nid_t alc861_adc_nids[1] = {
-       /* ADC0-2 */
-       0x08,
-};
+       defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
+       location = get_defcfg_location(defcfg);
+
+       num_pins = alc_auto_fill_multi_ios(codec, location);
+       if (num_pins > 0) {
+               struct snd_kcontrol_new *knew;
+
+               knew = alc_kcontrol_new(spec);
+               if (!knew)
+                       return -ENOMEM;
+               *knew = alc_auto_channel_mode_enum;
+               knew->name = kstrdup("Channel Mode", GFP_KERNEL);
+               if (!knew->name)
+                       return -ENOMEM;
 
-static const struct hda_input_mux alc861_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x3 },
-               { "Line", 0x1 },
-               { "CD", 0x4 },
-               { "Mixer", 0x5 },
-       },
-};
+               spec->multi_ios = num_pins;
+               spec->ext_channel_count = 2;
+               spec->multiout.num_dacs = num_pins + 1;
+       }
+       return 0;
+}
 
-static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
+/* filter out invalid adc_nids (and capsrc_nids) that don't give all
+ * active input pins
+ */
+static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       hda_nid_t mix, srcs[5];
-       int i, j, num;
+       const struct hda_input_mux *imux;
+       hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)];
+       hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)];
+       int i, n, nums;
 
-       if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
-               return 0;
-       num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
-       if (num < 0)
-               return 0;
-       for (i = 0; i < num; i++) {
-               unsigned int type;
-               type = get_wcaps_type(get_wcaps(codec, srcs[i]));
-               if (type != AC_WID_AUD_OUT)
-                       continue;
-               for (j = 0; j < spec->multiout.num_dacs; j++)
-                       if (spec->multiout.dac_nids[j] == srcs[i])
+       imux = spec->input_mux;
+       if (!imux)
+               return;
+       if (spec->dyn_adc_switch)
+               return;
+
+       nums = 0;
+       for (n = 0; n < spec->num_adc_nids; n++) {
+               hda_nid_t cap = spec->private_capsrc_nids[n];
+               int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
+               for (i = 0; i < imux->num_items; i++) {
+                       hda_nid_t pin = spec->imux_pins[i];
+                       if (pin) {
+                               if (get_connection_index(codec, cap, pin) < 0)
+                                       break;
+                       } else if (num_conns <= imux->items[i].index)
                                break;
-               if (j >= spec->multiout.num_dacs)
-                       return srcs[i];
+               }
+               if (i >= imux->num_items) {
+                       adc_nids[nums] = spec->private_adc_nids[n];
+                       capsrc_nids[nums++] = cap;
+               }
        }
-       return 0;
+       if (!nums) {
+               /* check whether ADC-switch is possible */
+               if (!alc_check_dyn_adc_switch(codec)) {
+                       printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
+                              " using fallback 0x%x\n",
+                              codec->chip_name, spec->private_adc_nids[0]);
+                       spec->num_adc_nids = 1;
+                       spec->auto_mic = 0;
+                       return;
+               }
+       } else if (nums != spec->num_adc_nids) {
+               memcpy(spec->private_adc_nids, adc_nids,
+                      nums * sizeof(hda_nid_t));
+               memcpy(spec->private_capsrc_nids, capsrc_nids,
+                      nums * sizeof(hda_nid_t));
+               spec->num_adc_nids = nums;
+       }
+
+       if (spec->auto_mic)
+               alc_auto_mic_check_imux(codec); /* check auto-mic setups */
+       else if (spec->input_mux->num_items == 1)
+               spec->num_adc_nids = 1; /* reduce to a single ADC */
 }
 
-/* fill in the dac_nids table from the parsed pin configuration */
-static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
-                                    const struct auto_pin_cfg *cfg)
+/*
+ * initialize ADC paths
+ */
+static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx)
 {
        struct alc_spec *spec = codec->spec;
-       int i;
-       hda_nid_t nid, dac;
+       hda_nid_t nid;
 
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       for (i = 0; i < cfg->line_outs; i++) {
-               nid = cfg->line_out_pins[i];
-               dac = alc861_look_for_dac(codec, nid);
-               if (!dac)
-                       continue;
-               spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+       nid = spec->adc_nids[adc_idx];
+       /* mute ADC */
+       if (nid_has_mute(codec, nid, HDA_INPUT)) {
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_IN_MUTE(0));
+               return;
        }
-       return 0;
+       if (!spec->capsrc_nids)
+               return;
+       nid = spec->capsrc_nids[adc_idx];
+       if (nid_has_mute(codec, nid, HDA_OUTPUT))
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_OUT_MUTE);
 }
 
-static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
-                                 hda_nid_t nid, int idx, unsigned int chs)
+static void alc_auto_init_input_src(struct hda_codec *codec)
 {
-       return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
-                          HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
-}
+       struct alc_spec *spec = codec->spec;
+       int c, nums;
 
-#define alc861_create_out_sw(codec, pfx, nid, chs) \
-       __alc861_create_out_sw(codec, pfx, nid, 0, chs)
+       for (c = 0; c < spec->num_adc_nids; c++)
+               alc_auto_init_adc(codec, c);
+       if (spec->dyn_adc_switch)
+               nums = 1;
+       else
+               nums = spec->num_adc_nids;
+       for (c = 0; c < nums; c++)
+               alc_mux_select(codec, 0, spec->cur_mux[c], true);
+}
 
-/* add playback controls from the parsed DAC table */
-static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
-                                            const struct auto_pin_cfg *cfg)
+/* add mic boosts if needed */
+static int alc_auto_add_mic_boost(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       static const char * const chname[4] = {
-               "Front", "Surround", NULL /*CLFE*/, "Side"
-       };
-       const char *pfx = alc_get_line_out_pfx(spec, true);
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, err;
+       int type_idx = 0;
        hda_nid_t nid;
-       int i, err, noutputs;
+       const char *prev_label = NULL;
 
-       noutputs = cfg->line_outs;
-       if (spec->multi_ios > 0)
-               noutputs += spec->multi_ios;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].type > AUTO_PIN_MIC)
+                       break;
+               nid = cfg->inputs[i].pin;
+               if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
+                       const char *label;
+                       char boost_label[32];
 
-       for (i = 0; i < noutputs; i++) {
-               nid = spec->multiout.dac_nids[i];
-               if (!nid)
-                       continue;
-               if (!pfx && i == 2) {
-                       /* Center/LFE */
-                       err = alc861_create_out_sw(codec, "Center", nid, 1);
-                       if (err < 0)
-                               return err;
-                       err = alc861_create_out_sw(codec, "LFE", nid, 2);
-                       if (err < 0)
-                               return err;
-               } else {
-                       const char *name = pfx;
-                       int index = i;
-                       if (!name) {
-                               name = chname[i];
-                               index = 0;
-                       }
-                       err = __alc861_create_out_sw(codec, name, nid, index, 3);
+                       label = hda_get_autocfg_input_label(codec, cfg, i);
+                       if (prev_label && !strcmp(label, prev_label))
+                               type_idx++;
+                       else
+                               type_idx = 0;
+                       prev_label = label;
+
+                       snprintf(boost_label, sizeof(boost_label),
+                                "%s Boost Volume", label);
+                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
+                                         boost_label, type_idx,
+                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
                        if (err < 0)
                                return err;
                }
@@ -16085,349 +3391,247 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
        return 0;
 }
 
-static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
+/* select or unmute the given capsrc route */
+static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
+                                   int idx)
+{
+       if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
+               snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
+                                        HDA_AMP_MUTE, 0);
+       } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
+               snd_hda_codec_write_cache(codec, cap, 0,
+                                         AC_VERB_SET_CONNECT_SEL, idx);
+       }
+}
+
+/* set the default connection to that pin */
+static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
 {
        struct alc_spec *spec = codec->spec;
-       int err;
-       hda_nid_t nid;
+       int i;
 
        if (!pin)
                return 0;
+       for (i = 0; i < spec->num_adc_nids; i++) {
+               hda_nid_t cap = spec->capsrc_nids ?
+                       spec->capsrc_nids[i] : spec->adc_nids[i];
+               int idx;
 
-       if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
-               nid = alc861_look_for_dac(codec, pin);
-               if (nid) {
-                       err = alc861_create_out_sw(codec, "Headphone", nid, 3);
-                       if (err < 0)
-                               return err;
-                       spec->multiout.hp_nid = nid;
-               }
+               idx = get_connection_index(codec, cap, pin);
+               if (idx < 0)
+                       continue;
+               select_or_unmute_capsrc(codec, cap, idx);
+               return i; /* return the found index */
        }
-       return 0;
+       return -1; /* not found */
 }
 
-/* create playback/capture controls for input pins */
-static int alc861_auto_create_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
+/* initialize some special cases for input sources */
+static void alc_init_special_input_src(struct hda_codec *codec)
 {
-       return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
+       struct alc_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < spec->autocfg.num_inputs; i++)
+               init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin);
 }
 
-static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid,
-                                             int pin_type, hda_nid_t dac)
+/* assign appropriate capture mixers */
+static void set_capture_mixer(struct hda_codec *codec)
 {
-       hda_nid_t mix, srcs[5];
-       int i, num;
+       struct alc_spec *spec = codec->spec;
+       static const struct snd_kcontrol_new *caps[2][3] = {
+               { alc_capture_mixer_nosrc1,
+                 alc_capture_mixer_nosrc2,
+                 alc_capture_mixer_nosrc3 },
+               { alc_capture_mixer1,
+                 alc_capture_mixer2,
+                 alc_capture_mixer3 },
+       };
 
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pin_type);
-       snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_UNMUTE);
-       if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
-               return;
-       num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
-       if (num < 0)
-               return;
-       for (i = 0; i < num; i++) {
-               unsigned int mute;
-               if (srcs[i] == dac || srcs[i] == 0x15)
-                       mute = AMP_IN_UNMUTE(i);
-               else
-                       mute = AMP_IN_MUTE(i);
-               snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                                   mute);
+       /* check whether either of ADC or MUX has a volume control */
+       if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) {
+               if (!spec->capsrc_nids)
+                       return; /* no volume */
+               if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT))
+                       return; /* no volume in capsrc, too */
+               spec->vol_in_capsrc = 1;
        }
-}
 
-static void alc861_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
+       if (spec->num_adc_nids > 0) {
+               int mux = 0;
+               int num_adcs = 0;
 
-       for (i = 0; i < spec->autocfg.line_outs; i++) {
-               hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               if (nid)
-                       alc861_auto_set_output_and_unmute(codec, nid, pin_type,
-                                                         spec->multiout.dac_nids[i]);
+               if (spec->input_mux && spec->input_mux->num_items > 1)
+                       mux = 1;
+               if (spec->auto_mic) {
+                       num_adcs = 1;
+                       mux = 0;
+               } else if (spec->dyn_adc_switch)
+                       num_adcs = 1;
+               if (!num_adcs) {
+                       if (spec->num_adc_nids > 3)
+                               spec->num_adc_nids = 3;
+                       else if (!spec->num_adc_nids)
+                               return;
+                       num_adcs = spec->num_adc_nids;
+               }
+               spec->cap_mixer = caps[mux][num_adcs - 1];
        }
 }
 
-static void alc861_auto_init_hp_out(struct hda_codec *codec)
+/*
+ * standard auto-parser initializations
+ */
+static void alc_auto_init_std(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-
-       if (spec->autocfg.hp_outs)
-               alc861_auto_set_output_and_unmute(codec,
-                                                 spec->autocfg.hp_pins[0],
-                                                 PIN_HP,
-                                                 spec->multiout.hp_nid);
-       if (spec->autocfg.speaker_outs)
-               alc861_auto_set_output_and_unmute(codec,
-                                                 spec->autocfg.speaker_pins[0],
-                                                 PIN_OUT,
-                                                 spec->multiout.dac_nids[0]);
+       alc_auto_init_multi_out(codec);
+       alc_auto_init_extra_out(codec);
+       alc_auto_init_analog_input(codec);
+       alc_auto_init_input_src(codec);
+       alc_auto_init_digital(codec);
+       if (spec->unsol_event)
+               alc_inithook(codec);
 }
 
-static void alc861_auto_init_analog_input(struct hda_codec *codec)
+/*
+ * Digital-beep handlers
+ */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+#define set_beep_amp(spec, nid, idx, dir) \
+       ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+
+static const struct snd_pci_quirk beep_white_list[] = {
+       SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
+       SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
+       SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
+       SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
+       {}
+};
+
+static inline int has_cdefine_beep(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               if (nid >= 0x0c && nid <= 0x11)
-                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
-       }
+       const struct snd_pci_quirk *q;
+       q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
+       if (q)
+               return q->value;
+       return spec->cdefine.enable_pcbeep;
 }
+#else
+#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#define has_cdefine_beep(codec)                0
+#endif
 
 /* parse the BIOS configuration and set up the alc_spec */
 /* return 1 if successful, 0 if the proper config is not found,
  * or a negative error code
  */
-static int alc861_parse_auto_config(struct hda_codec *codec)
+static int alc_parse_auto_config(struct hda_codec *codec,
+                                const hda_nid_t *ignore_nids,
+                                const hda_nid_t *ssid_nids)
 {
        struct alc_spec *spec = codec->spec;
        int err;
-       static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc861_ignore);
+                                          ignore_nids);
        if (err < 0)
                return err;
-       if (!spec->autocfg.line_outs)
+       if (!spec->autocfg.line_outs) {
+               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
+                       spec->multiout.max_channels = 2;
+                       spec->no_analog = 1;
+                       goto dig_only;
+               }
                return 0; /* can't find valid BIOS pin config */
-
-       err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
+       }
+       err = alc_auto_fill_dac_nids(codec);
+       if (err < 0)
+               return err;
+       err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
        if (err < 0)
                return err;
-       err = alc_auto_add_multi_channel_mode(codec);
+       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
+       err = alc_auto_create_hp_out(codec);
        if (err < 0)
                return err;
-       err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
+       err = alc_auto_create_speaker_out(codec);
        if (err < 0)
                return err;
-       err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
+       err = alc_auto_create_input_ctls(codec);
        if (err < 0)
                return err;
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
+ dig_only:
        alc_auto_parse_digital(codec);
 
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
+       if (!spec->no_analog)
+               alc_remove_invalid_adc_nids(codec);
 
-       add_verb(spec, alc861_auto_init_verbs);
-
-       spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux[0];
+       if (ssid_nids)
+               alc_ssid_check(codec, ssid_nids);
 
-       spec->adc_nids = alc861_adc_nids;
-       spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
-       set_capture_mixer(codec);
+       if (!spec->no_analog) {
+               alc_auto_check_switches(codec);
+               err = alc_auto_add_mic_boost(codec);
+               if (err < 0)
+                       return err;
+       }
 
-       alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
+       if (spec->kctls.list)
+               add_mixer(spec, spec->kctls.list);
 
        return 1;
 }
 
-/* additional initialization for auto-configuration model */
-static void alc861_auto_init(struct hda_codec *codec)
+static int alc880_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       alc861_auto_init_multi_out(codec);
-       alc861_auto_init_hp_out(codec);
-       alc861_auto_init_analog_input(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc861_loopbacks[] = {
-       { 0x15, HDA_INPUT, 0 },
-       { 0x15, HDA_INPUT, 1 },
-       { 0x15, HDA_INPUT, 2 },
-       { 0x15, HDA_INPUT, 3 },
-       { } /* end */
-};
-#endif
-
-
-/*
- * configuration and preset
- */
-static const char * const alc861_models[ALC861_MODEL_LAST] = {
-       [ALC861_3ST]            = "3stack",
-       [ALC660_3ST]            = "3stack-660",
-       [ALC861_3ST_DIG]        = "3stack-dig",
-       [ALC861_6ST_DIG]        = "6stack-dig",
-       [ALC861_UNIWILL_M31]    = "uniwill-m31",
-       [ALC861_TOSHIBA]        = "toshiba",
-       [ALC861_ASUS]           = "asus",
-       [ALC861_ASUS_LAPTOP]    = "asus-laptop",
-       [ALC861_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk alc861_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
-       SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
-       SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
-       SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
-       SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
-       SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
-       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
-       /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
-        *        Any other models that need this preset?
-        */
-       /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
-       SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
-       SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
-       SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
-       SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
-       SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
-       /* FIXME: the below seems conflict */
-       /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
-       SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
-       SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
-       {}
-};
-
-static const struct alc_config_preset alc861_presets[] = {
-       [ALC861_3ST] = {
-               .mixers = { alc861_3ST_mixer },
-               .init_verbs = { alc861_threestack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
-               .dac_nids = alc861_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
-               .channel_mode = alc861_threestack_modes,
-               .need_dac_fix = 1,
-               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
-               .adc_nids = alc861_adc_nids,
-               .input_mux = &alc861_capture_source,
-       },
-       [ALC861_3ST_DIG] = {
-               .mixers = { alc861_base_mixer },
-               .init_verbs = { alc861_threestack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
-               .dac_nids = alc861_dac_nids,
-               .dig_out_nid = ALC861_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
-               .channel_mode = alc861_threestack_modes,
-               .need_dac_fix = 1,
-               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
-               .adc_nids = alc861_adc_nids,
-               .input_mux = &alc861_capture_source,
-       },
-       [ALC861_6ST_DIG] = {
-               .mixers = { alc861_base_mixer },
-               .init_verbs = { alc861_base_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
-               .dac_nids = alc861_dac_nids,
-               .dig_out_nid = ALC861_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
-               .channel_mode = alc861_8ch_modes,
-               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
-               .adc_nids = alc861_adc_nids,
-               .input_mux = &alc861_capture_source,
-       },
-       [ALC660_3ST] = {
-               .mixers = { alc861_3ST_mixer },
-               .init_verbs = { alc861_threestack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc660_dac_nids),
-               .dac_nids = alc660_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
-               .channel_mode = alc861_threestack_modes,
-               .need_dac_fix = 1,
-               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
-               .adc_nids = alc861_adc_nids,
-               .input_mux = &alc861_capture_source,
-       },
-       [ALC861_UNIWILL_M31] = {
-               .mixers = { alc861_uniwill_m31_mixer },
-               .init_verbs = { alc861_uniwill_m31_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
-               .dac_nids = alc861_dac_nids,
-               .dig_out_nid = ALC861_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
-               .channel_mode = alc861_uniwill_m31_modes,
-               .need_dac_fix = 1,
-               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
-               .adc_nids = alc861_adc_nids,
-               .input_mux = &alc861_capture_source,
-       },
-       [ALC861_TOSHIBA] = {
-               .mixers = { alc861_toshiba_mixer },
-               .init_verbs = { alc861_base_init_verbs,
-                               alc861_toshiba_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
-               .dac_nids = alc861_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
-               .adc_nids = alc861_adc_nids,
-               .input_mux = &alc861_capture_source,
-               .unsol_event = alc861_toshiba_unsol_event,
-               .init_hook = alc861_toshiba_automute,
-       },
-       [ALC861_ASUS] = {
-               .mixers = { alc861_asus_mixer },
-               .init_verbs = { alc861_asus_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
-               .dac_nids = alc861_dac_nids,
-               .dig_out_nid = ALC861_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
-               .channel_mode = alc861_asus_modes,
-               .need_dac_fix = 1,
-               .hp_nid = 0x06,
-               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
-               .adc_nids = alc861_adc_nids,
-               .input_mux = &alc861_capture_source,
-       },
-       [ALC861_ASUS_LAPTOP] = {
-               .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
-               .init_verbs = { alc861_asus_init_verbs,
-                               alc861_asus_laptop_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861_dac_nids),
-               .dac_nids = alc861_dac_nids,
-               .dig_out_nid = ALC861_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .need_dac_fix = 1,
-               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
-               .adc_nids = alc861_adc_nids,
-               .input_mux = &alc861_capture_source,
-       },
-};
+       static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; 
+       return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
+}
 
-/* Pin config fixes */
-enum {
-       PINFIX_FSC_AMILO_PI1505,
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static const struct hda_amp_list alc880_loopbacks[] = {
+       { 0x0b, HDA_INPUT, 0 },
+       { 0x0b, HDA_INPUT, 1 },
+       { 0x0b, HDA_INPUT, 2 },
+       { 0x0b, HDA_INPUT, 3 },
+       { 0x0b, HDA_INPUT, 4 },
+       { } /* end */
 };
+#endif
 
-static const struct alc_fixup alc861_fixups[] = {
-       [PINFIX_FSC_AMILO_PI1505] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x0b, 0x0221101f }, /* HP */
-                       { 0x0f, 0x90170310 }, /* speaker */
-                       { }
-               }
-       },
-};
+/*
+ * board setups
+ */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#define alc_board_config \
+       snd_hda_check_board_config
+#define alc_board_codec_sid_config \
+       snd_hda_check_board_codec_sid_config
+#include "alc_quirks.c"
+#else
+#define alc_board_config(codec, nums, models, tbl)     -1
+#define alc_board_codec_sid_config(codec, nums, models, tbl)   -1
+#define setup_preset(codec, x) /* NOP */
+#endif
 
-static const struct snd_pci_quirk alc861_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
-       {}
-};
+/*
+ * OK, here we have finally the patch for ALC880
+ */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc880_quirks.c"
+#endif
 
-static int patch_alc861(struct hda_codec *codec)
+static int patch_alc880(struct hda_codec *codec)
 {
        struct alc_spec *spec;
        int board_config;
@@ -16439,970 +3643,281 @@ static int patch_alc861(struct hda_codec *codec)
 
        codec->spec = spec;
 
-        board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
-                                                 alc861_models,
-                                                 alc861_cfg_tbl);
+       spec->mixer_nid = 0x0b;
+       spec->need_dac_fix = 1;
 
+       board_config = alc_board_config(codec, ALC880_MODEL_LAST,
+                                       alc880_models, alc880_cfg_tbl);
        if (board_config < 0) {
                printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
                       codec->chip_name);
-               board_config = ALC861_AUTO;
-       }
-
-       if (board_config == ALC861_AUTO) {
-               alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
-               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+               board_config = ALC_MODEL_AUTO;
        }
 
-       if (board_config == ALC861_AUTO) {
+       if (board_config == ALC_MODEL_AUTO) {
                /* automatic parse from the BIOS config */
-               err = alc861_parse_auto_config(codec);
+               err = alc880_parse_auto_config(codec);
                if (err < 0) {
                        alc_free(codec);
                        return err;
-               } else if (!err) {
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
                        printk(KERN_INFO
                               "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using base mode...\n");
-                  board_config = ALC861_3ST_DIG;
+                              "from BIOS.  Using 3-stack mode...\n");
+                       board_config = ALC880_3ST;
                }
+#endif
        }
 
-       err = snd_hda_attach_beep_device(codec, 0x23);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
-       }
-
-       if (board_config != ALC861_AUTO)
-               setup_preset(codec, &alc861_presets[board_config]);
-
-       spec->stream_analog_playback = &alc861_pcm_analog_playback;
-       spec->stream_analog_capture = &alc861_pcm_analog_capture;
+       if (board_config != ALC_MODEL_AUTO)
+               setup_preset(codec, &alc880_presets[board_config]);
 
-       spec->stream_digital_playback = &alc861_pcm_digital_playback;
-       spec->stream_digital_capture = &alc861_pcm_digital_capture;
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
+       }
 
-       if (!spec->cap_mixer)
+       if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
-       set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
 
-       spec->vmaster_nid = 0x03;
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       }
 
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
+       spec->vmaster_nid = 0x0c;
 
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC861_AUTO) {
-               spec->init_hook = alc861_auto_init;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-               spec->power_hook = alc_power_eapd;
-#endif
-       }
+       if (board_config == ALC_MODEL_AUTO)
+               spec->init_hook = alc_auto_init_std;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc861_loopbacks;
+               spec->loopback.amplist = alc880_loopbacks;
 #endif
 
        return 0;
 }
 
-/*
- * ALC861-VD support
- *
- * Based on ALC882
- *
- * In addition, an independent DAC
- */
-#define ALC861VD_DIGOUT_NID    0x06
-
-static const hda_nid_t alc861vd_dac_nids[4] = {
-       /* front, surr, clfe, side surr */
-       0x02, 0x03, 0x04, 0x05
-};
-
-/* dac_nids for ALC660vd are in a different order - according to
- * Realtek's driver.
- * This should probably result in a different mixer for 6stack models
- * of ALC660vd codecs, but for now there is only 3stack mixer
- * - and it is the same as in 861vd.
- * adc_nids in ALC660vd are (is) the same as in 861vd
- */
-static const hda_nid_t alc660vd_dac_nids[3] = {
-       /* front, rear, clfe, rear_surr */
-       0x02, 0x04, 0x03
-};
-
-static const hda_nid_t alc861vd_adc_nids[1] = {
-       /* ADC0 */
-       0x09,
-};
-
-static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
-
-/* input MUX */
-/* FIXME: should be a matrix-type input source selection */
-static const struct hda_input_mux alc861vd_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-static const struct hda_input_mux alc861vd_dallas_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-       },
-};
-
-static const struct hda_input_mux alc861vd_hp_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "ATAPI Mic", 0x1 },
-       },
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
-       { 2, NULL }
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc861vd_6stack_ch6_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc861vd_6stack_ch8_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
-       { 6, alc861vd_6stack_ch6_init },
-       { 8, alc861vd_6stack_ch8_init },
-};
-
-static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
-
-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
- *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
- */
-static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
-                               HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
-                               HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-
-       { } /* end */
-};
-
-/* Pin assignment: Speaker=0x14, HP = 0x15,
- *                 Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
- */
-static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-/* Pin assignment: Speaker=0x14, Line-out = 0x15,
- *                 Front Mic=0x18, ATAPI Mic = 0x19,
- */
-static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-
-       { } /* end */
-};
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc861vd_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0 and set the default input to mic-in
-        */
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
-        * the analog-loopback mixer widget
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
-       /*
-        * Set up output mixers (0x02 - 0x05)
-        */
-       /* set vol=0 to output mixers */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {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},
-
-       /* set up input amps for analog loopback */
-       /* Amp Indices: DAC = 0, mixer = 1 */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-       { }
-};
-
-/*
- * 3-stack pin configuration:
- * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
- */
-static const struct hda_verb alc861vd_3stack_init_verbs[] = {
-       /*
-        * Set pin mode and muting
-        */
-       /* set front pin widgets 0x14 for output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Mic (rear) pin: input vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Front Mic pin: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin: input */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line-2 In: Headphone output (output 0 - 0x0c) */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* CD pin widget for input */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       { }
-};
 
 /*
- * 6-stack pin configuration:
+ * ALC260 support
  */
-static const struct hda_verb alc861vd_6stack_init_verbs[] = {
-       /*
-        * Set pin mode and muting
-        */
-       /* set front pin widgets 0x14 for output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Rear Pin: output 1 (0x0d) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* CLFE Pin: output 2 (0x0e) */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* Side Pin: output 3 (0x0f) */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-
-       /* Mic (rear) pin: input vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Front Mic pin: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin: input */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line-2 In: Headphone output (output 0 - 0x0c) */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* CD pin widget for input */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       { }
-};
-
-static const struct hda_verb alc861vd_eapd_verbs[] = {
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-static const struct hda_verb alc660vd_eapd_verbs[] = {
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {}
-};
-
-static void alc861vd_lenovo_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
-{
-       alc_hp_automute(codec);
-       alc88x_simple_mic_automute(codec);
-}
-
-static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
-                                       unsigned int res)
+static int alc260_parse_auto_config(struct hda_codec *codec)
 {
-       switch (res >> 26) {
-       case ALC880_MIC_EVENT:
-               alc88x_simple_mic_automute(codec);
-               break;
-       default:
-               alc_sku_unsol_event(codec, res);
-               break;
-       }
+       static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
+       static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
+       return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
 }
 
-static const struct hda_verb alc861vd_dallas_verbs[] = {
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {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},
-
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static const struct hda_amp_list alc260_loopbacks[] = {
+       { 0x07, HDA_INPUT, 0 },
+       { 0x07, HDA_INPUT, 1 },
+       { 0x07, HDA_INPUT, 2 },
+       { 0x07, HDA_INPUT, 3 },
+       { 0x07, HDA_INPUT, 4 },
        { } /* end */
 };
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc861vd_dallas_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc861vd_loopbacks     alc880_loopbacks
 #endif
 
-/* pcm configuration: identical with ALC880 */
-#define alc861vd_pcm_analog_playback   alc880_pcm_analog_playback
-#define alc861vd_pcm_analog_capture    alc880_pcm_analog_capture
-#define alc861vd_pcm_digital_playback  alc880_pcm_digital_playback
-#define alc861vd_pcm_digital_capture   alc880_pcm_digital_capture
-
 /*
- * configuration and preset
+ * Pin config fixes
  */
-static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
-       [ALC660VD_3ST]          = "3stack-660",
-       [ALC660VD_3ST_DIG]      = "3stack-660-digout",
-       [ALC660VD_ASUS_V1S]     = "asus-v1s",
-       [ALC861VD_3ST]          = "3stack",
-       [ALC861VD_3ST_DIG]      = "3stack-digout",
-       [ALC861VD_6ST_DIG]      = "6stack-digout",
-       [ALC861VD_LENOVO]       = "lenovo",
-       [ALC861VD_DALLAS]       = "dallas",
-       [ALC861VD_HP]           = "hp",
-       [ALC861VD_AUTO]         = "auto",
+enum {
+       PINFIX_HP_DC5750,
 };
 
-static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
-       SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
-       SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
-       /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
-       SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
-       SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
-       SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
-       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
-       /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
-       SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
-       SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
-       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
-       SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
-       SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
-       {}
+static const struct alc_fixup alc260_fixups[] = {
+       [PINFIX_HP_DC5750] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x11, 0x90130110 }, /* speaker */
+                       { }
+               }
+       },
 };
 
-static const struct alc_config_preset alc861vd_presets[] = {
-       [ALC660VD_3ST] = {
-               .mixers = { alc861vd_3st_mixer },
-               .init_verbs = { alc861vd_volume_init_verbs,
-                                alc861vd_3stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
-               .dac_nids = alc660vd_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
-               .channel_mode = alc861vd_3stack_2ch_modes,
-               .input_mux = &alc861vd_capture_source,
-       },
-       [ALC660VD_3ST_DIG] = {
-               .mixers = { alc861vd_3st_mixer },
-               .init_verbs = { alc861vd_volume_init_verbs,
-                                alc861vd_3stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
-               .dac_nids = alc660vd_dac_nids,
-               .dig_out_nid = ALC861VD_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
-               .channel_mode = alc861vd_3stack_2ch_modes,
-               .input_mux = &alc861vd_capture_source,
-       },
-       [ALC861VD_3ST] = {
-               .mixers = { alc861vd_3st_mixer },
-               .init_verbs = { alc861vd_volume_init_verbs,
-                                alc861vd_3stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
-               .dac_nids = alc861vd_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
-               .channel_mode = alc861vd_3stack_2ch_modes,
-               .input_mux = &alc861vd_capture_source,
-       },
-       [ALC861VD_3ST_DIG] = {
-               .mixers = { alc861vd_3st_mixer },
-               .init_verbs = { alc861vd_volume_init_verbs,
-                                alc861vd_3stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
-               .dac_nids = alc861vd_dac_nids,
-               .dig_out_nid = ALC861VD_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
-               .channel_mode = alc861vd_3stack_2ch_modes,
-               .input_mux = &alc861vd_capture_source,
-       },
-       [ALC861VD_6ST_DIG] = {
-               .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
-               .init_verbs = { alc861vd_volume_init_verbs,
-                               alc861vd_6stack_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
-               .dac_nids = alc861vd_dac_nids,
-               .dig_out_nid = ALC861VD_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
-               .channel_mode = alc861vd_6stack_modes,
-               .input_mux = &alc861vd_capture_source,
-       },
-       [ALC861VD_LENOVO] = {
-               .mixers = { alc861vd_lenovo_mixer },
-               .init_verbs = { alc861vd_volume_init_verbs,
-                               alc861vd_3stack_init_verbs,
-                               alc861vd_eapd_verbs,
-                               alc861vd_lenovo_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
-               .dac_nids = alc660vd_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
-               .channel_mode = alc861vd_3stack_2ch_modes,
-               .input_mux = &alc861vd_capture_source,
-               .unsol_event = alc861vd_lenovo_unsol_event,
-               .setup = alc861vd_lenovo_setup,
-               .init_hook = alc861vd_lenovo_init_hook,
-       },
-       [ALC861VD_DALLAS] = {
-               .mixers = { alc861vd_dallas_mixer },
-               .init_verbs = { alc861vd_dallas_verbs },
-               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
-               .dac_nids = alc861vd_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
-               .channel_mode = alc861vd_3stack_2ch_modes,
-               .input_mux = &alc861vd_dallas_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc861vd_dallas_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC861VD_HP] = {
-               .mixers = { alc861vd_hp_mixer },
-               .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
-               .dac_nids = alc861vd_dac_nids,
-               .dig_out_nid = ALC861VD_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
-               .channel_mode = alc861vd_3stack_2ch_modes,
-               .input_mux = &alc861vd_hp_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc861vd_dallas_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC660VD_ASUS_V1S] = {
-               .mixers = { alc861vd_lenovo_mixer },
-               .init_verbs = { alc861vd_volume_init_verbs,
-                               alc861vd_3stack_init_verbs,
-                               alc861vd_eapd_verbs,
-                               alc861vd_lenovo_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
-               .dac_nids = alc660vd_dac_nids,
-               .dig_out_nid = ALC861VD_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
-               .channel_mode = alc861vd_3stack_2ch_modes,
-               .input_mux = &alc861vd_capture_source,
-               .unsol_event = alc861vd_lenovo_unsol_event,
-               .setup = alc861vd_lenovo_setup,
-               .init_hook = alc861vd_lenovo_init_hook,
-       },
+static const struct snd_pci_quirk alc260_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
+       {}
 };
 
 /*
- * BIOS auto configuration
  */
-static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
-}
-
-
-static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
-                               hda_nid_t nid, int pin_type, int dac_idx)
-{
-       alc_set_pin_output(codec, nid, pin_type);
-}
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc260_quirks.c"
+#endif
 
-static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
+static int patch_alc260(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i <= HDA_SIDE; i++) {
-               hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               if (nid)
-                       alc861vd_auto_set_output_and_unmute(codec, nid,
-                                                           pin_type, i);
-       }
-}
+       struct alc_spec *spec;
+       int err, board_config;
 
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
 
-static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t pin;
+       codec->spec = spec;
 
-       pin = spec->autocfg.hp_pins[0];
-       if (pin) /* connect to front and use dac 0 */
-               alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin)
-               alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
-}
+       spec->mixer_nid = 0x07;
 
-#define ALC861VD_PIN_CD_NID            ALC880_PIN_CD_NID
+       board_config = alc_board_config(codec, ALC260_MODEL_LAST,
+                                       alc260_models, alc260_cfg_tbl);
+       if (board_config < 0) {
+               snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                          codec->chip_name);
+               board_config = ALC_MODEL_AUTO;
+       }
 
-static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
+       if (board_config == ALC_MODEL_AUTO) {
+               alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
+               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+       }
 
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               if (alc_is_input_pin(codec, nid)) {
-                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
-                       if (nid != ALC861VD_PIN_CD_NID &&
-                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
-                               snd_hda_codec_write(codec, nid, 0,
-                                               AC_VERB_SET_AMP_GAIN_MUTE,
-                                               AMP_OUT_MUTE);
+       if (board_config == ALC_MODEL_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc260_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                       board_config = ALC260_BASIC;
                }
+#endif
        }
-}
-
-#define alc861vd_auto_init_input_src   alc882_auto_init_input_src
-
-#define alc861vd_idx_to_mixer_vol(nid)         ((nid) + 0x02)
-#define alc861vd_idx_to_mixer_switch(nid)      ((nid) + 0x0c)
-
-/* add playback controls from the parsed DAC table */
-/* Based on ALC880 version. But ALC861VD has separate,
- * different NIDs for mute/unmute switch and volume control */
-static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       static const char * const chname[4] = {
-               "Front", "Surround", "CLFE", "Side"
-       };
-       const char *pfx = alc_get_line_out_pfx(spec, true);
-       hda_nid_t nid_v, nid_s;
-       int i, err, noutputs;
 
-       noutputs = cfg->line_outs;
-       if (spec->multi_ios > 0)
-               noutputs += spec->multi_ios;
+       if (board_config != ALC_MODEL_AUTO)
+               setup_preset(codec, &alc260_presets[board_config]);
 
-       for (i = 0; i < noutputs; i++) {
-               if (!spec->multiout.dac_nids[i])
-                       continue;
-               nid_v = alc861vd_idx_to_mixer_vol(
-                               alc880_dac_to_idx(
-                                       spec->multiout.dac_nids[i]));
-               nid_s = alc861vd_idx_to_mixer_switch(
-                               alc880_dac_to_idx(
-                                       spec->multiout.dac_nids[i]));
-
-               if (!pfx && i == 2) {
-                       /* Center/LFE */
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                             "Center",
-                                         HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                             "LFE",
-                                         HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                            "Center",
-                                         HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
-                                                             HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                            "LFE",
-                                         HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
-                                                             HDA_INPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       const char *name = pfx;
-                       int index = i;
-                       if (!name) {
-                               name = chname[i];
-                               index = 0;
-                       }
-                       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                               name, index,
-                                         HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                              name, index,
-                                         HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
-                                                             HDA_INPUT));
-                       if (err < 0)
-                               return err;
-               }
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
        }
-       return 0;
-}
-
-/* add playback controls for speaker and HP outputs */
-/* Based on ALC880 version. But ALC861VD has separate,
- * different NIDs for mute/unmute switch and volume control */
-static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
-                                       hda_nid_t pin, const char *pfx)
-{
-       hda_nid_t nid_v, nid_s;
-       int err;
 
-       if (!pin)
-               return 0;
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
 
-       if (alc880_is_fixed_pin(pin)) {
-               nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
-               /* specify the DAC as the extra output */
-               if (!spec->multiout.hp_nid)
-                       spec->multiout.hp_nid = nid_v;
-               else
-                       spec->multiout.extra_out_nid[0] = nid_v;
-               /* control HP volume/switch on the output mixer amp */
-               nid_v = alc861vd_idx_to_mixer_vol(
-                               alc880_fixed_pin_idx(pin));
-               nid_s = alc861vd_idx_to_mixer_switch(
-                               alc880_fixed_pin_idx(pin));
-
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
-                                 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
-                                 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
-               if (err < 0)
-                       return err;
-       } else if (alc880_is_multi_pin(pin)) {
-               /* set manual connection */
-               /* we have only a switch on HP-out PIN */
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
-                                 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-               if (err < 0)
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
                        return err;
+               }
+               set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
        }
-       return 0;
-}
-
-/* parse the BIOS configuration and set up the alc_spec
- * return 1 if successful, 0 if the proper config is not found,
- * or a negative error code
- * Based on ALC880 version - had to change it to override
- * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
-static int alc861vd_parse_auto_config(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc861vd_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs)
-               return 0; /* can't find valid BIOS pin config */
-
-       err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_add_multi_channel_mode(codec);
-       if (err < 0)
-               return err;
-       err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc861vd_auto_create_extra_out(spec,
-                                            spec->autocfg.speaker_pins[0],
-                                            "Speaker");
-       if (err < 0)
-               return err;
-       err = alc861vd_auto_create_extra_out(spec,
-                                            spec->autocfg.hp_pins[0],
-                                            "Headphone");
-       if (err < 0)
-               return err;
-       err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
 
-       add_verb(spec, alc861vd_volume_init_verbs);
-
-       spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux[0];
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
+       spec->vmaster_nid = 0x08;
 
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
+       codec->patch_ops = alc_patch_ops;
+       if (board_config == ALC_MODEL_AUTO)
+               spec->init_hook = alc_auto_init_std;
+       spec->shutup = alc_eapd_shutup;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       if (!spec->loopback.amplist)
+               spec->loopback.amplist = alc260_loopbacks;
+#endif
 
-       return 1;
+       return 0;
 }
 
-/* additional initialization for auto-configuration model */
-static void alc861vd_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc861vd_auto_init_multi_out(codec);
-       alc861vd_auto_init_hp_out(codec);
-       alc861vd_auto_init_analog_input(codec);
-       alc861vd_auto_init_input_src(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
-}
 
+/*
+ * ALC882/883/885/888/889 support
+ *
+ * ALC882 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration.  Each pin widget can choose any input DACs and a mixer.
+ * Each ADC is connected from a mixer of all inputs.  This makes possible
+ * 6-channel independent captures.
+ *
+ * In addition, an independent DAC for the multi-playback (not used in this
+ * driver yet).
+ */
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+#define alc882_loopbacks       alc880_loopbacks
+#endif
+
+/*
+ * Pin config fixes
+ */
 enum {
-       ALC660VD_FIX_ASUS_GPIO1
+       PINFIX_ABIT_AW9D_MAX,
+       PINFIX_LENOVO_Y530,
+       PINFIX_PB_M5210,
+       PINFIX_ACER_ASPIRE_7736,
 };
 
-/* reset GPIO1 */
-static const struct alc_fixup alc861vd_fixups[] = {
-       [ALC660VD_FIX_ASUS_GPIO1] = {
+static const struct alc_fixup alc882_fixups[] = {
+       [PINFIX_ABIT_AW9D_MAX] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x15, 0x01080104 }, /* side */
+                       { 0x16, 0x01011012 }, /* rear */
+                       { 0x17, 0x01016011 }, /* clfe */
+                       { }
+               }
+       },
+       [PINFIX_LENOVO_Y530] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x15, 0x99130112 }, /* rear int speakers */
+                       { 0x16, 0x99130111 }, /* subwoofer */
+                       { }
+               }
+       },
+       [PINFIX_PB_M5210] = {
                .type = ALC_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
-                       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
-                       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-                       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
-                       { }
+                       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+                       {}
                }
        },
+       [PINFIX_ACER_ASPIRE_7736] = {
+               .type = ALC_FIXUP_SKU,
+               .v.sku = ALC_FIXUP_SKU_IGNORE,
+       },
 };
 
-static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
+static const struct snd_pci_quirk alc882_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
+       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
+       SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+       SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
        {}
 };
 
-static int patch_alc861vd(struct hda_codec *codec)
+/*
+ * BIOS auto configuration
+ */
+/* almost identical with ALC880 parser... */
+static int alc882_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
+}
+
+/*
+ */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc882_quirks.c"
+#endif
+
+static int patch_alc882(struct hda_codec *codec)
 {
        struct alc_spec *spec;
        int err, board_config;
@@ -17413,2030 +3928,1126 @@ static int patch_alc861vd(struct hda_codec *codec)
 
        codec->spec = spec;
 
-       board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
-                                                 alc861vd_models,
-                                                 alc861vd_cfg_tbl);
+       spec->mixer_nid = 0x0b;
+
+       switch (codec->vendor_id) {
+       case 0x10ec0882:
+       case 0x10ec0885:
+               break;
+       default:
+               /* ALC883 and variants */
+               alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+               break;
+       }
+
+       board_config = alc_board_config(codec, ALC882_MODEL_LAST,
+                                       alc882_models, alc882_cfg_tbl);
 
-       if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
+       if (board_config < 0)
+               board_config = alc_board_codec_sid_config(codec,
+                       ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
+
+       if (board_config < 0) {
                printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
                       codec->chip_name);
-               board_config = ALC861VD_AUTO;
+               board_config = ALC_MODEL_AUTO;
        }
 
-       if (board_config == ALC861VD_AUTO) {
-               alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
+       if (board_config == ALC_MODEL_AUTO) {
+               alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
                alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
        }
 
-       if (board_config == ALC861VD_AUTO) {
+       alc_auto_parse_customize_define(codec);
+
+       if (board_config == ALC_MODEL_AUTO) {
                /* automatic parse from the BIOS config */
-               err = alc861vd_parse_auto_config(codec);
+               err = alc882_parse_auto_config(codec);
                if (err < 0) {
                        alc_free(codec);
                        return err;
-               } else if (!err) {
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
                        printk(KERN_INFO
                               "hda_codec: Cannot set up configuration "
                               "from BIOS.  Using base mode...\n");
-                       board_config = ALC861VD_3ST;
+                       board_config = ALC882_3ST_DIG;
                }
+#endif
        }
 
-       err = snd_hda_attach_beep_device(codec, 0x23);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
-       }
-
-       if (board_config != ALC861VD_AUTO)
-               setup_preset(codec, &alc861vd_presets[board_config]);
+       if (board_config != ALC_MODEL_AUTO)
+               setup_preset(codec, &alc882_presets[board_config]);
 
-       if (codec->vendor_id == 0x10ec0660) {
-               /* always turn on EAPD */
-               add_verb(spec, alc660vd_eapd_verbs);
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
        }
 
-       spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
-       spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
-
-       spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
-       spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
 
-       if (!spec->adc_nids) {
-               spec->adc_nids = alc861vd_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
+       if (!spec->no_analog && has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
        }
-       if (!spec->capsrc_nids)
-               spec->capsrc_nids = alc861vd_capsrc_nids;
-
-       set_capture_mixer(codec);
-       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-
-       spec->vmaster_nid = 0x02;
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
+       spec->vmaster_nid = 0x0c;
+
        codec->patch_ops = alc_patch_ops;
+       if (board_config == ALC_MODEL_AUTO)
+               spec->init_hook = alc_auto_init_std;
 
-       if (board_config == ALC861VD_AUTO)
-               spec->init_hook = alc861vd_auto_init;
-       spec->shutup = alc_eapd_shutup;
+       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc861vd_loopbacks;
+               spec->loopback.amplist = alc882_loopbacks;
 #endif
 
        return 0;
 }
 
-/*
- * ALC662 support
- *
- * ALC662 is almost identical with ALC880 but has cleaner and more flexible
- * configuration.  Each pin widget can choose any input DACs and a mixer.
- * Each ADC is connected from a mixer of all inputs.  This makes possible
- * 6-channel independent captures.
- *
- * In addition, an independent DAC for the multi-playback (not used in this
- * driver yet).
- */
-#define ALC662_DIGOUT_NID      0x06
-#define ALC662_DIGIN_NID       0x0a
-
-static const hda_nid_t alc662_dac_nids[3] = {
-       /* front, rear, clfe */
-       0x02, 0x03, 0x04
-};
-
-static const hda_nid_t alc272_dac_nids[2] = {
-       0x02, 0x03
-};
-
-static const hda_nid_t alc662_adc_nids[2] = {
-       /* ADC1-2 */
-       0x09, 0x08
-};
-
-static const hda_nid_t alc272_adc_nids[1] = {
-       /* ADC1-2 */
-       0x08,
-};
-
-static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
-static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
-
-
-/* input MUX */
-/* FIXME: should be a matrix-type input source selection */
-static const struct hda_input_mux alc662_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x1 },
-               { "Line", 0x2 },
-       },
-};
-
-static const struct hda_input_mux alc663_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x2 },
-       },
-};
-
-#if 0 /* set to 1 for testing other input sources below */
-static const struct hda_input_mux alc272_nc10_capture_source = {
-       .num_items = 16,
-       .items = {
-               { "Autoselect Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-               { "In-0x02", 0x2 },
-               { "In-0x03", 0x3 },
-               { "In-0x04", 0x4 },
-               { "In-0x05", 0x5 },
-               { "In-0x06", 0x6 },
-               { "In-0x07", 0x7 },
-               { "In-0x08", 0x8 },
-               { "In-0x09", 0x9 },
-               { "In-0x0a", 0x0a },
-               { "In-0x0b", 0x0b },
-               { "In-0x0c", 0x0c },
-               { "In-0x0d", 0x0d },
-               { "In-0x0e", 0x0e },
-               { "In-0x0f", 0x0f },
-       },
-};
-#endif
-
-/*
- * 2ch mode
- */
-static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
-       { 2, NULL }
-};
 
 /*
- * 2ch mode
+ * ALC262 support
  */
-static const struct hda_verb alc662_3ST_ch2_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
+static int alc262_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
+}
 
 /*
- * 6ch mode
+ * Pin config fixes
  */
-static const struct hda_verb alc662_3ST_ch6_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
+enum {
+       PINFIX_FSC_H270,
+       PINFIX_HP_Z200,
 };
 
-static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
-       { 2, alc662_3ST_ch2_init },
-       { 6, alc662_3ST_ch6_init },
+static const struct alc_fixup alc262_fixups[] = {
+       [PINFIX_FSC_H270] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0221142f }, /* front HP */
+                       { 0x1b, 0x0121141f }, /* rear HP */
+                       { }
+               }
+       },
+       [PINFIX_HP_Z200] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x16, 0x99130120 }, /* internal speaker */
+                       { }
+               }
+       },
 };
 
-/*
- * 2ch mode
- */
-static const struct hda_verb alc662_sixstack_ch6_init[] = {
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
+static const struct snd_pci_quirk alc262_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
+       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
+       {}
 };
 
-/*
- * 6ch mode
- */
-static const struct hda_verb alc662_sixstack_ch8_init[] = {
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
 
-static const struct hda_channel_mode alc662_5stack_modes[2] = {
-       { 2, alc662_sixstack_ch6_init },
-       { 6, alc662_sixstack_ch8_init },
-};
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+#define alc262_loopbacks       alc880_loopbacks
+#endif
 
-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
- *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+/*
  */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc262_quirks.c"
+#endif
 
-static const struct snd_kcontrol_new alc662_base_mixer[] = {
-       /* output mixer control */
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-
-       /*Input mixer control */
-       HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       ALC262_HIPPO_MASTER_SWITCH,
-
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+static int patch_alc262(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int board_config;
+       int err;
 
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
 
-static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
+       codec->spec = spec;
 
-static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+       spec->mixer_nid = 0x0b;
 
-static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+#if 0
+       /* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
+        * under-run
+        */
+       {
+       int tmp;
+       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
+       tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
+       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
+       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
+       }
+#endif
+       alc_auto_parse_customize_define(codec);
 
-static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
+       alc_fix_pll_init(codec, 0x20, 0x0a, 10);
 
-static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+       board_config = alc_board_config(codec, ALC262_MODEL_LAST,
+                                       alc262_models, alc262_cfg_tbl);
 
-static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       if (board_config < 0) {
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
+               board_config = ALC_MODEL_AUTO;
+       }
 
-       { } /* end */
-};
+       if (board_config == ALC_MODEL_AUTO) {
+               alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
+               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+       }
 
-static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+       if (board_config == ALC_MODEL_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc262_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                       board_config = ALC262_BASIC;
+               }
+#endif
+       }
 
-static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
+       if (board_config != ALC_MODEL_AUTO)
+               setup_preset(codec, &alc262_presets[board_config]);
 
-static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
+       }
 
-static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
 
-static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+       if (!spec->no_analog && has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       }
 
-static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume",
-                               &alc663_asus_two_bind_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
-static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
+       spec->vmaster_nid = 0x0c;
 
-static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
+       codec->patch_ops = alc_patch_ops;
+       if (board_config == ALC_MODEL_AUTO)
+               spec->init_hook = alc_auto_init_std;
+       spec->shutup = alc_eapd_shutup;
 
-static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       { } /* end */
-};
+       alc_init_jacks(codec);
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       if (!spec->loopback.amplist)
+               spec->loopback.amplist = alc262_loopbacks;
+#endif
 
-static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+       return 0;
+}
 
-static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
+/*
+ *  ALC268
+ */
+/* bind Beep switches of both NID 0x0f and 0x10 */
+static const struct hda_bind_ctls alc268_bind_beep_sw = {
        .ops = &snd_hda_bind_sw,
        .values = {
-               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
                0
        },
 };
 
-static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
-       HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
-       HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
-       HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
-       HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
-       HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
-       HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
-       HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
-       HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-
-static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb alc662_init_verbs[] = {
-       /* ADC: mute amp left and right */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* Front Pin: output 0 (0x0c) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Rear Pin: output 1 (0x0d) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* CLFE Pin: output 2 (0x0e) */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Mic (rear) pin: input vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Front Mic pin: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin: input */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line-2 In: Headphone output (output 0 - 0x0c) */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* CD pin widget for input */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
+static const struct snd_kcontrol_new alc268_beep_mixer[] = {
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
+       HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
        { }
 };
 
-static const struct hda_verb alc662_eapd_init_verbs[] = {
-       /* always trun on EAPD */
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/* set PCBEEP vol = 0, mute connections */
+static const struct hda_verb alc268_beep_init_verbs[] = {
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
        { }
 };
 
-static const struct hda_verb alc662_sue_init_verbs[] = {
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
-       {}
-};
+/*
+ * BIOS auto configuration
+ */
+static int alc268_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       struct alc_spec *spec = codec->spec;
+       int err = alc_parse_auto_config(codec, NULL, alc268_ssids);
+       if (err > 0) {
+               if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
+                       add_mixer(spec, alc268_beep_mixer);
+                       add_verb(spec, alc268_beep_init_verbs);
+               }
+       }
+       return err;
+}
 
-static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+/*
+ */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc268_quirks.c"
+#endif
 
-/* Set Unsolicited Event*/
-static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+static int patch_alc268(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int board_config;
+       int i, has_beep, err;
 
-static const struct hda_verb alc663_m51va_init_verbs[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
 
-static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       codec->spec = spec;
 
-static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       /* ALC268 has no aa-loopback mixer */
 
-static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       board_config = alc_board_config(codec, ALC268_MODEL_LAST,
+                                       alc268_models, alc268_cfg_tbl);
 
-static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x0},   /* Headphone */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},   /* Headphone */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       if (board_config < 0)
+               board_config = alc_board_codec_sid_config(codec,
+                       ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
 
-static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       if (board_config < 0) {
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
+               board_config = ALC_MODEL_AUTO;
+       }
 
-static const struct hda_verb alc663_g71v_init_verbs[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
-       /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
+       if (board_config == ALC_MODEL_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc268_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                       board_config = ALC268_3ST;
+               }
+#endif
+       }
 
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+       if (board_config != ALC_MODEL_AUTO)
+               setup_preset(codec, &alc268_presets[board_config]);
 
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
-       {}
-};
+       has_beep = 0;
+       for (i = 0; i < spec->num_mixers; i++) {
+               if (spec->mixers[i] == alc268_beep_mixer) {
+                       has_beep = 1;
+                       break;
+               }
+       }
 
-static const struct hda_verb alc663_g50v_init_verbs[] = {
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+       if (has_beep) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
+                       /* override the amp caps for beep generator */
+                       snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
+                                         (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
+                                         (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                         (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                         (0 << AC_AMPCAP_MUTE_SHIFT));
+       }
 
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
+       }
 
-static const struct hda_verb alc662_ecs_init_verbs[] = {
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
 
-static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       spec->vmaster_nid = 0x02;
 
-static const struct hda_verb alc272_dell_init_verbs[] = {
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       codec->patch_ops = alc_patch_ops;
+       if (board_config == ALC_MODEL_AUTO)
+               spec->init_hook = alc_auto_init_std;
+       spec->shutup = alc_eapd_shutup;
 
-static const struct hda_verb alc663_mode7_init_verbs[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
-       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       alc_init_jacks(codec);
 
-static const struct hda_verb alc663_mode8_init_verbs[] = {
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {}
-};
+       return 0;
+}
 
-static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-       { } /* end */
+/*
+ * ALC269
+ */
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+#define alc269_loopbacks       alc880_loopbacks
+#endif
+
+static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+       /* NID is set in alc_build_pcms */
+       .ops = {
+               .open = alc_playback_pcm_open,
+               .prepare = alc_playback_pcm_prepare,
+               .cleanup = alc_playback_pcm_cleanup
+       },
 };
 
-static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-       { } /* end */
+static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+       /* NID is set in alc_build_pcms */
 };
 
-static void alc662_lenovo_101e_setup(struct hda_codec *codec)
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int alc269_mic2_for_mute_led(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.line_out_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->automute = 1;
-       spec->detect_line = 1;
-       spec->automute_lines = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
+       switch (codec->subsystem_id) {
+       case 0x103c1586:
+               return 1;
+       }
+       return 0;
 }
 
-static void alc662_eeepc_setup(struct hda_codec *codec)
+static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
 {
-       struct alc_spec *spec = codec->spec;
-
-       alc262_hippo1_setup(codec);
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
+       /* update mute-LED according to the speaker mute state */
+       if (nid == 0x01 || nid == 0x14) {
+               int pinval;
+               if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
+                   HDA_AMP_MUTE)
+                       pinval = 0x24;
+               else
+                       pinval = 0x20;
+               /* mic2 vref pin is used for mute LED control */
+               snd_hda_codec_update_cache(codec, 0x19, 0,
+                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                          pinval);
+       }
+       return alc_check_power_status(codec, nid);
 }
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+
+/* different alc269-variants */
+enum {
+       ALC269_TYPE_ALC269VA,
+       ALC269_TYPE_ALC269VB,
+       ALC269_TYPE_ALC269VC,
+};
 
-static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
+/*
+ * BIOS auto configuration
+ */
+static int alc269_parse_auto_config(struct hda_codec *codec)
 {
+       static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
+       static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
        struct alc_spec *spec = codec->spec;
+       const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ?
+               alc269va_ssids : alc269_ssids;
 
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x1b;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
+       return alc_parse_auto_config(codec, alc269_ignore, ssids);
 }
 
-static void alc663_m51va_setup(struct hda_codec *codec)
+static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
 {
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x21;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x12;
-       spec->int_mic.mux_idx = 9;
-       spec->auto_mic = 1;
+       int val = alc_read_coef_idx(codec, 0x04);
+       if (power_up)
+               val |= 1 << 11;
+       else
+               val &= ~(1 << 11);
+       alc_write_coef_idx(codec, 0x04, val);
 }
 
-/* ***************** Mode1 ******************************/
-static void alc663_mode1_setup(struct hda_codec *codec)
+static void alc269_shutup(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x21;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
+               alc269_toggle_power_output(codec, 0);
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+               alc269_toggle_power_output(codec, 0);
+               msleep(150);
+       }
 }
 
-/* ***************** Mode2 ******************************/
-static void alc662_mode2_setup(struct hda_codec *codec)
+#ifdef SND_HDA_NEEDS_RESUME
+static int alc269_resume(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-}
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+               alc269_toggle_power_output(codec, 0);
+               msleep(150);
+       }
 
-/* ***************** Mode3 ******************************/
-static void alc663_mode3_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x21;
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-}
+       codec->patch_ops.init(codec);
 
-/* ***************** Mode4 ******************************/
-static void alc663_mode4_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x21;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute_mixer_nid[1] = 0x0e;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-}
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+               alc269_toggle_power_output(codec, 1);
+               msleep(200);
+       }
 
-/* ***************** Mode5 ******************************/
-static void alc663_mode5_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute_mixer_nid[1] = 0x0e;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
+               alc269_toggle_power_output(codec, 1);
+
+       snd_hda_codec_resume_amp(codec);
+       snd_hda_codec_resume_cache(codec);
+       hda_call_check_power_status(codec, 0x01);
+       return 0;
 }
+#endif /* SND_HDA_NEEDS_RESUME */
 
-/* ***************** Mode6 ******************************/
-static void alc663_mode6_setup(struct hda_codec *codec)
+static void alc269_fixup_hweq(struct hda_codec *codec,
+                              const struct alc_fixup *fix, int action)
 {
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0c;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
+       int coef;
+
+       if (action != ALC_FIXUP_ACT_INIT)
+               return;
+       coef = alc_read_coef_idx(codec, 0x1e);
+       alc_write_coef_idx(codec, 0x1e, coef | 0x80);
 }
 
-/* ***************** Mode7 ******************************/
-static void alc663_mode7_setup(struct hda_codec *codec)
+static void alc271_fixup_dmic(struct hda_codec *codec,
+                             const struct alc_fixup *fix, int action)
 {
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.hp_pins[0] = 0x21;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x17;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x19;
-       spec->int_mic.mux_idx = 1;
-       spec->auto_mic = 1;
-}
+       static const struct hda_verb verbs[] = {
+               {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
+               {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
+               {}
+       };
+       unsigned int cfg;
 
-/* ***************** Mode8 ******************************/
-static void alc663_mode8_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x21;
-       spec->autocfg.hp_pins[1] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x17;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_PIN;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x12;
-       spec->int_mic.mux_idx = 9;
-       spec->auto_mic = 1;
+       if (strcmp(codec->chip_name, "ALC271X"))
+               return;
+       cfg = snd_hda_codec_get_pincfg(codec, 0x12);
+       if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
+               snd_hda_sequence_write(codec, verbs);
 }
 
-static void alc663_g71v_setup(struct hda_codec *codec)
+static void alc269_fixup_pcm_44k(struct hda_codec *codec,
+                                const struct alc_fixup *fix, int action)
 {
        struct alc_spec *spec = codec->spec;
-       spec->autocfg.hp_pins[0] = 0x21;
-       spec->autocfg.line_out_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-       spec->detect_line = 1;
-       spec->automute_lines = 1;
-       spec->ext_mic.pin = 0x18;
-       spec->ext_mic.mux_idx = 0;
-       spec->int_mic.pin = 0x12;
-       spec->int_mic.mux_idx = 9;
-       spec->auto_mic = 1;
-}
-
-#define alc663_g50v_setup      alc663_m51va_setup
-
-static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       ALC262_HIPPO_MASTER_SWITCH,
 
-       HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
-       /* Master Playback automatically created from Speaker and Headphone */
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc662_loopbacks       alc880_loopbacks
-#endif
-
-
-/* pcm configuration: identical with ALC880 */
-#define alc662_pcm_analog_playback     alc880_pcm_analog_playback
-#define alc662_pcm_analog_capture      alc880_pcm_analog_capture
-#define alc662_pcm_digital_playback    alc880_pcm_digital_playback
-#define alc662_pcm_digital_capture     alc880_pcm_digital_capture
+       if (action != ALC_FIXUP_ACT_PROBE)
+               return;
 
-/*
- * configuration and preset
- */
-static const char * const alc662_models[ALC662_MODEL_LAST] = {
-       [ALC662_3ST_2ch_DIG]    = "3stack-dig",
-       [ALC662_3ST_6ch_DIG]    = "3stack-6ch-dig",
-       [ALC662_3ST_6ch]        = "3stack-6ch",
-       [ALC662_5ST_DIG]        = "5stack-dig",
-       [ALC662_LENOVO_101E]    = "lenovo-101e",
-       [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
-       [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
-       [ALC662_ECS] = "ecs",
-       [ALC663_ASUS_M51VA] = "m51va",
-       [ALC663_ASUS_G71V] = "g71v",
-       [ALC663_ASUS_H13] = "h13",
-       [ALC663_ASUS_G50V] = "g50v",
-       [ALC663_ASUS_MODE1] = "asus-mode1",
-       [ALC662_ASUS_MODE2] = "asus-mode2",
-       [ALC663_ASUS_MODE3] = "asus-mode3",
-       [ALC663_ASUS_MODE4] = "asus-mode4",
-       [ALC663_ASUS_MODE5] = "asus-mode5",
-       [ALC663_ASUS_MODE6] = "asus-mode6",
-       [ALC663_ASUS_MODE7] = "asus-mode7",
-       [ALC663_ASUS_MODE8] = "asus-mode8",
-       [ALC272_DELL]           = "dell",
-       [ALC272_DELL_ZM1]       = "dell-zm1",
-       [ALC272_SAMSUNG_NC10]   = "samsung-nc10",
-       [ALC662_AUTO]           = "auto",
-};
+       /* Due to a hardware problem on Lenovo Ideadpad, we need to
+        * fix the sample rate of analog I/O to 44.1kHz
+        */
+       spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
+       spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
+}
 
-static const struct snd_pci_quirk alc662_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
-       SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
-       SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
-       SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
-       SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
-       SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
-       SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
-       SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
-       SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
-       /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
-       SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
-       /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
-       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
-       SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
-       SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
-       SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
-       SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
-       SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
-                     ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
-       SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
-       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
-                     ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
-       SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
-       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
-       SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
-                                       ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
-                          ALC663_ASUS_H13),
-       SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
-       {}
+enum {
+       ALC269_FIXUP_SONY_VAIO,
+       ALC275_FIXUP_SONY_VAIO_GPIO2,
+       ALC269_FIXUP_DELL_M101Z,
+       ALC269_FIXUP_SKU_IGNORE,
+       ALC269_FIXUP_ASUS_G73JW,
+       ALC269_FIXUP_LENOVO_EAPD,
+       ALC275_FIXUP_SONY_HWEQ,
+       ALC271_FIXUP_DMIC,
+       ALC269_FIXUP_PCM_44K,
 };
 
-static const struct alc_config_preset alc662_presets[] = {
-       [ALC662_3ST_2ch_DIG] = {
-               .mixers = { alc662_3ST_2ch_mixer },
-               .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .dig_in_nid = ALC662_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .input_mux = &alc662_capture_source,
-       },
-       [ALC662_3ST_6ch_DIG] = {
-               .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
-               .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .dig_in_nid = ALC662_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
-               .channel_mode = alc662_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc662_capture_source,
-       },
-       [ALC662_3ST_6ch] = {
-               .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
-               .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
-               .channel_mode = alc662_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc662_capture_source,
-       },
-       [ALC662_5ST_DIG] = {
-               .mixers = { alc662_base_mixer, alc662_chmode_mixer },
-               .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .dig_in_nid = ALC662_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
-               .channel_mode = alc662_5stack_modes,
-               .input_mux = &alc662_capture_source,
-       },
-       [ALC662_LENOVO_101E] = {
-               .mixers = { alc662_lenovo_101e_mixer },
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc662_sue_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .input_mux = &alc662_lenovo_101e_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc662_lenovo_101e_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC662_ASUS_EEEPC_P701] = {
-               .mixers = { alc662_eeepc_p701_mixer },
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc662_eeepc_sue_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc662_eeepc_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC662_ASUS_EEEPC_EP20] = {
-               .mixers = { alc662_eeepc_ep20_mixer,
-                           alc662_chmode_mixer },
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc662_eeepc_ep20_sue_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
-               .channel_mode = alc662_3ST_6ch_modes,
-               .input_mux = &alc662_lenovo_101e_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc662_eeepc_ep20_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC662_ECS] = {
-               .mixers = { alc662_ecs_mixer },
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc662_ecs_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc662_eeepc_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC663_ASUS_M51VA] = {
-               .mixers = { alc663_m51va_mixer },
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_m51va_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_m51va_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC663_ASUS_G71V] = {
-               .mixers = { alc663_g71v_mixer },
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_g71v_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_g71v_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC663_ASUS_H13] = {
-               .mixers = { alc663_m51va_mixer },
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_m51va_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .setup = alc663_m51va_setup,
-               .unsol_event = alc_sku_unsol_event,
-               .init_hook = alc_inithook,
-       },
-       [ALC663_ASUS_G50V] = {
-               .mixers = { alc663_g50v_mixer },
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_g50v_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
-               .channel_mode = alc662_3ST_6ch_modes,
-               .input_mux = &alc663_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_g50v_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC663_ASUS_MODE1] = {
-               .mixers = { alc663_m51va_mixer },
-               .cap_mixer = alc662_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_21jd_amic_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .hp_nid = 0x03,
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_mode1_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC662_ASUS_MODE2] = {
-               .mixers = { alc662_1bjd_mixer },
-               .cap_mixer = alc662_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc662_1bjd_amic_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc662_mode2_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC663_ASUS_MODE3] = {
-               .mixers = { alc663_two_hp_m1_mixer },
-               .cap_mixer = alc662_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_two_hp_amic_m1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .hp_nid = 0x03,
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_mode3_setup,
-               .init_hook = alc_inithook,
+static const struct alc_fixup alc269_fixups[] = {
+       [ALC269_FIXUP_SONY_VAIO] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
+                       {}
+               }
        },
-       [ALC663_ASUS_MODE4] = {
-               .mixers = { alc663_asus_21jd_clfe_mixer },
-               .cap_mixer = alc662_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_21jd_amic_init_verbs},
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .hp_nid = 0x03,
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_mode4_setup,
-               .init_hook = alc_inithook,
+       [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
+                       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
+                       {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_SONY_VAIO
        },
-       [ALC663_ASUS_MODE5] = {
-               .mixers = { alc663_asus_15jd_clfe_mixer },
-               .cap_mixer = alc662_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_15jd_amic_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .hp_nid = 0x03,
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_mode5_setup,
-               .init_hook = alc_inithook,
+       [ALC269_FIXUP_DELL_M101Z] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Enables internal speaker */
+                       {0x20, AC_VERB_SET_COEF_INDEX, 13},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
+                       {}
+               }
        },
-       [ALC663_ASUS_MODE6] = {
-               .mixers = { alc663_two_hp_m2_mixer },
-               .cap_mixer = alc662_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_two_hp_amic_m2_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .hp_nid = 0x03,
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_mode6_setup,
-               .init_hook = alc_inithook,
+       [ALC269_FIXUP_SKU_IGNORE] = {
+               .type = ALC_FIXUP_SKU,
+               .v.sku = ALC_FIXUP_SKU_IGNORE,
        },
-       [ALC663_ASUS_MODE7] = {
-               .mixers = { alc663_mode7_mixer },
-               .cap_mixer = alc662_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_mode7_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .hp_nid = 0x03,
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_mode7_setup,
-               .init_hook = alc_inithook,
+       [ALC269_FIXUP_ASUS_G73JW] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x17, 0x99130111 }, /* subwoofer */
+                       { }
+               }
        },
-       [ALC663_ASUS_MODE8] = {
-               .mixers = { alc663_mode8_mixer },
-               .cap_mixer = alc662_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_mode8_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
-               .hp_nid = 0x03,
-               .dac_nids = alc662_dac_nids,
-               .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_mode8_setup,
-               .init_hook = alc_inithook,
+       [ALC269_FIXUP_LENOVO_EAPD] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+                       {}
+               }
        },
-       [ALC272_DELL] = {
-               .mixers = { alc663_m51va_mixer },
-               .cap_mixer = alc272_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc272_dell_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc272_dac_nids),
-               .dac_nids = alc272_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .adc_nids = alc272_adc_nids,
-               .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
-               .capsrc_nids = alc272_capsrc_nids,
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_m51va_setup,
-               .init_hook = alc_inithook,
+       [ALC275_FIXUP_SONY_HWEQ] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc269_fixup_hweq,
+               .chained = true,
+               .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
        },
-       [ALC272_DELL_ZM1] = {
-               .mixers = { alc663_m51va_mixer },
-               .cap_mixer = alc662_auto_capture_mixer,
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc272_dell_zm1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc272_dac_nids),
-               .dac_nids = alc272_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .adc_nids = alc662_adc_nids,
-               .num_adc_nids = 1,
-               .capsrc_nids = alc662_capsrc_nids,
-               .channel_mode = alc662_3ST_2ch_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_m51va_setup,
-               .init_hook = alc_inithook,
+       [ALC271_FIXUP_DMIC] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc271_fixup_dmic,
        },
-       [ALC272_SAMSUNG_NC10] = {
-               .mixers = { alc272_nc10_mixer },
-               .init_verbs = { alc662_init_verbs,
-                               alc662_eapd_init_verbs,
-                               alc663_21jd_amic_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc272_dac_nids),
-               .dac_nids = alc272_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
-               .channel_mode = alc662_3ST_2ch_modes,
-               /*.input_mux = &alc272_nc10_capture_source,*/
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc663_mode4_setup,
-               .init_hook = alc_inithook,
+       [ALC269_FIXUP_PCM_44K] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc269_fixup_pcm_44k,
        },
 };
 
+static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+       SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
+       SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
+       SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
+       SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
+       SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+       SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
+       SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
+       SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
+       {}
+};
 
-/*
- * BIOS auto configuration
- */
 
-/* convert from MIX nid to DAC */
-static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
+static int alc269_fill_coef(struct hda_codec *codec)
 {
-       hda_nid_t list[5];
-       int i, num;
+       int val;
 
-       num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
-       for (i = 0; i < num; i++) {
-               if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
-                       return list[i];
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
+               alc_write_coef_idx(codec, 0xf, 0x960b);
+               alc_write_coef_idx(codec, 0xe, 0x8817);
        }
-       return 0;
-}
-
-/* go down to the selector widget before the mixer */
-static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
-{
-       hda_nid_t srcs[5];
-       int num = snd_hda_get_connections(codec, pin, srcs,
-                                         ARRAY_SIZE(srcs));
-       if (num != 1 ||
-           get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
-               return pin;
-       return srcs[0];
-}
-
-/* get MIX nid connected to the given pin targeted to DAC */
-static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
-                                  hda_nid_t dac)
-{
-       hda_nid_t mix[5];
-       int i, num;
 
-       pin = alc_go_down_to_selector(codec, pin);
-       num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
-       for (i = 0; i < num; i++) {
-               if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
-                       return mix[i];
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
+               alc_write_coef_idx(codec, 0xf, 0x960b);
+               alc_write_coef_idx(codec, 0xe, 0x8814);
        }
-       return 0;
-}
 
-/* select the connection from pin to DAC if needed */
-static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
-                              hda_nid_t dac)
-{
-       hda_nid_t mix[5];
-       int i, num;
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+               val = alc_read_coef_idx(codec, 0x04);
+               /* Power up output pin */
+               alc_write_coef_idx(codec, 0x04, val | (1<<11));
+       }
 
-       pin = alc_go_down_to_selector(codec, pin);
-       num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
-       if (num < 2)
-               return 0;
-       for (i = 0; i < num; i++) {
-               if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
-                       snd_hda_codec_update_cache(codec, pin, 0,
-                                                  AC_VERB_SET_CONNECT_SEL, i);
-                       return 0;
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+               val = alc_read_coef_idx(codec, 0xd);
+               if ((val & 0x0c00) >> 10 != 0x1) {
+                       /* Capless ramp up clock control */
+                       alc_write_coef_idx(codec, 0xd, val | (1<<10));
+               }
+               val = alc_read_coef_idx(codec, 0x17);
+               if ((val & 0x01c0) >> 6 != 0x4) {
+                       /* Class D power on reset */
+                       alc_write_coef_idx(codec, 0x17, val | (1<<7));
                }
        }
+
+       val = alc_read_coef_idx(codec, 0xd); /* Class D */
+       alc_write_coef_idx(codec, 0xd, val | (1<<14));
+
+       val = alc_read_coef_idx(codec, 0x4); /* HP */
+       alc_write_coef_idx(codec, 0x4, val | (1<<11));
+
        return 0;
 }
 
-/* look for an empty DAC slot */
-static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
+/*
+ */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc269_quirks.c"
+#endif
+
+static int patch_alc269(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t srcs[5];
-       int i, j, num;
+       struct alc_spec *spec;
+       int board_config, coef;
+       int err;
 
-       pin = alc_go_down_to_selector(codec, pin);
-       num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
-       for (i = 0; i < num; i++) {
-               hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
-               if (!nid)
-                       continue;
-               for (j = 0; j < spec->multiout.num_dacs; j++)
-                       if (spec->multiout.dac_nids[j] == nid)
-                               break;
-               if (j >= spec->multiout.num_dacs)
-                       return nid;
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       spec->mixer_nid = 0x0b;
+
+       alc_auto_parse_customize_define(codec);
+
+       if (codec->vendor_id == 0x10ec0269) {
+               spec->codec_variant = ALC269_TYPE_ALC269VA;
+               coef = alc_read_coef_idx(codec, 0);
+               if ((coef & 0x00f0) == 0x0010) {
+                       if (codec->bus->pci->subsystem_vendor == 0x1025 &&
+                           spec->cdefine.platform_type == 1) {
+                               alc_codec_rename(codec, "ALC271X");
+                       } else if ((coef & 0xf000) == 0x2000) {
+                               alc_codec_rename(codec, "ALC259");
+                       } else if ((coef & 0xf000) == 0x3000) {
+                               alc_codec_rename(codec, "ALC258");
+                       } else if ((coef & 0xfff0) == 0x3010) {
+                               alc_codec_rename(codec, "ALC277");
+                       } else {
+                               alc_codec_rename(codec, "ALC269VB");
+                       }
+                       spec->codec_variant = ALC269_TYPE_ALC269VB;
+               } else if ((coef & 0x00f0) == 0x0020) {
+                       if (coef == 0xa023)
+                               alc_codec_rename(codec, "ALC259");
+                       else if (coef == 0x6023)
+                               alc_codec_rename(codec, "ALC281X");
+                       else if (codec->bus->pci->subsystem_vendor == 0x17aa &&
+                                codec->bus->pci->subsystem_device == 0x21f3)
+                               alc_codec_rename(codec, "ALC3202");
+                       else
+                               alc_codec_rename(codec, "ALC269VC");
+                       spec->codec_variant = ALC269_TYPE_ALC269VC;
+               } else
+                       alc_fix_pll_init(codec, 0x20, 0x04, 15);
+               alc269_fill_coef(codec);
        }
-       return 0;
-}
 
-/* fill in the dac_nids table from the parsed pin configuration */
-static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
-                                    const struct auto_pin_cfg *cfg)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-       hda_nid_t dac;
+       board_config = alc_board_config(codec, ALC269_MODEL_LAST,
+                                       alc269_models, alc269_cfg_tbl);
 
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       for (i = 0; i < cfg->line_outs; i++) {
-               dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]);
-               if (!dac)
-                       continue;
-               spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+       if (board_config < 0) {
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
+               board_config = ALC_MODEL_AUTO;
        }
-       return 0;
-}
 
-static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
-                                      hda_nid_t nid, int idx, unsigned int chs)
-{
-       return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx,
-                          HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
-}
+       if (board_config == ALC_MODEL_AUTO) {
+               alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
+               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+       }
 
-static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
-                                     hda_nid_t nid, int idx, unsigned int chs)
-{
-       return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
-                          HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
-}
+       if (board_config == ALC_MODEL_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc269_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                       board_config = ALC269_BASIC;
+               }
+#endif
+       }
 
-#define alc662_add_vol_ctl(spec, pfx, nid, chs) \
-       __alc662_add_vol_ctl(spec, pfx, nid, 0, chs)
-#define alc662_add_sw_ctl(spec, pfx, nid, chs) \
-       __alc662_add_sw_ctl(spec, pfx, nid, 0, chs)
-#define alc662_add_stereo_vol(spec, pfx, nid) \
-       alc662_add_vol_ctl(spec, pfx, nid, 3)
-#define alc662_add_stereo_sw(spec, pfx, nid) \
-       alc662_add_sw_ctl(spec, pfx, nid, 3)
+       if (board_config != ALC_MODEL_AUTO)
+               setup_preset(codec, &alc269_presets[board_config]);
 
-/* add playback controls from the parsed DAC table */
-static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       struct alc_spec *spec = codec->spec;
-       static const char * const chname[4] = {
-               "Front", "Surround", NULL /*CLFE*/, "Side"
-       };
-       const char *pfx = alc_get_line_out_pfx(spec, true);
-       hda_nid_t nid, mix, pin;
-       int i, err, noutputs;
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
+       }
 
-       noutputs = cfg->line_outs;
-       if (spec->multi_ios > 0)
-               noutputs += spec->multi_ios;
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
 
-       for (i = 0; i < noutputs; i++) {
-               nid = spec->multiout.dac_nids[i];
-               if (!nid)
-                       continue;
-               if (i >= cfg->line_outs)
-                       pin = spec->multi_io[i - 1].pin;
-               else
-                       pin = cfg->line_out_pins[i];
-               mix = alc_auto_dac_to_mix(codec, pin, nid);
-               if (!mix)
-                       continue;
-               if (!pfx && i == 2) {
-                       /* Center/LFE */
-                       err = alc662_add_vol_ctl(spec, "Center", nid, 1);
-                       if (err < 0)
-                               return err;
-                       err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
-                       if (err < 0)
-                               return err;
-                       err = alc662_add_sw_ctl(spec, "Center", mix, 1);
-                       if (err < 0)
-                               return err;
-                       err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
-                       if (err < 0)
-                               return err;
-               } else {
-                       const char *name = pfx;
-                       int index = i;
-                       if (!name) {
-                               name = chname[i];
-                               index = 0;
-                       }
-                       err = __alc662_add_vol_ctl(spec, name, nid, index, 3);
-                       if (err < 0)
-                               return err;
-                       err = __alc662_add_sw_ctl(spec, name, mix, index, 3);
-                       if (err < 0)
-                               return err;
+       if (!spec->no_analog && has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
                }
+               set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
        }
-       return 0;
-}
-
-/* add playback controls for speaker and HP outputs */
-/* return DAC nid if any new DAC is assigned */
-static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
-                                       const char *pfx)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t nid, mix;
-       int err;
 
-       if (!pin)
-               return 0;
-       nid = alc_auto_look_for_dac(codec, pin);
-       if (!nid) {
-               /* the corresponding DAC is already occupied */
-               if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
-                       return 0; /* no way */
-               /* create a switch only */
-               return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
-                                  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       }
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
-       mix = alc_auto_dac_to_mix(codec, pin, nid);
-       if (!mix)
-               return 0;
-       err = alc662_add_vol_ctl(spec, pfx, nid, 3);
-       if (err < 0)
-               return err;
-       err = alc662_add_sw_ctl(spec, pfx, mix, 3);
-       if (err < 0)
-               return err;
-       return nid;
-}
+       spec->vmaster_nid = 0x02;
 
-/* create playback/capture controls for input pins */
-#define alc662_auto_create_input_ctls \
-       alc882_auto_create_input_ctls
+       codec->patch_ops = alc_patch_ops;
+#ifdef SND_HDA_NEEDS_RESUME
+       codec->patch_ops.resume = alc269_resume;
+#endif
+       if (board_config == ALC_MODEL_AUTO)
+               spec->init_hook = alc_auto_init_std;
+       spec->shutup = alc269_shutup;
 
-static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type,
-                                             hda_nid_t dac)
-{
-       int i, num;
-       hda_nid_t srcs[HDA_MAX_CONNECTIONS];
+       alc_init_jacks(codec);
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       if (!spec->loopback.amplist)
+               spec->loopback.amplist = alc269_loopbacks;
+       if (alc269_mic2_for_mute_led(codec))
+               codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
+#endif
 
-       alc_set_pin_output(codec, nid, pin_type);
-       num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
-       for (i = 0; i < num; i++) {
-               if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
-                       continue;
-               /* need the manual connection? */
-               if (num > 1)
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_CONNECT_SEL, i);
-               /* unmute mixer widget inputs */
-               snd_hda_codec_write(codec, srcs[i], 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_IN_UNMUTE(0));
-               snd_hda_codec_write(codec, srcs[i], 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_IN_UNMUTE(1));
-               return;
-       }
+       return 0;
 }
 
-static void alc662_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int pin_type = get_pin_type(spec->autocfg.line_out_type);
-       int i;
-
-       for (i = 0; i <= HDA_SIDE; i++) {
-               hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               if (nid)
-                       alc662_auto_set_output_and_unmute(codec, nid, pin_type,
-                                       spec->multiout.dac_nids[i]);
-       }
-}
+/*
+ * ALC861
+ */
 
-static void alc662_auto_init_hp_out(struct hda_codec *codec)
+static int alc861_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t pin;
-
-       pin = spec->autocfg.hp_pins[0];
-       if (pin)
-               alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
-                                                 spec->multiout.hp_nid);
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin)
-               alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
-                                       spec->multiout.extra_out_nid[0]);
+       static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
+       return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
 }
 
-#define ALC662_PIN_CD_NID              ALC880_PIN_CD_NID
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static const struct hda_amp_list alc861_loopbacks[] = {
+       { 0x15, HDA_INPUT, 0 },
+       { 0x15, HDA_INPUT, 1 },
+       { 0x15, HDA_INPUT, 2 },
+       { 0x15, HDA_INPUT, 3 },
+       { } /* end */
+};
+#endif
+
 
-static void alc662_auto_init_analog_input(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
+/* Pin config fixes */
+enum {
+       PINFIX_FSC_AMILO_PI1505,
+};
 
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               if (alc_is_input_pin(codec, nid)) {
-                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
-                       if (nid != ALC662_PIN_CD_NID &&
-                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
-                               snd_hda_codec_write(codec, nid, 0,
-                                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                                   AMP_OUT_MUTE);
+static const struct alc_fixup alc861_fixups[] = {
+       [PINFIX_FSC_AMILO_PI1505] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x0b, 0x0221101f }, /* HP */
+                       { 0x0f, 0x90170310 }, /* speaker */
+                       { }
                }
-       }
-}
+       },
+};
 
-#define alc662_auto_init_input_src     alc882_auto_init_input_src
+static const struct snd_pci_quirk alc861_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
+       {}
+};
 
 /*
- * multi-io helper
  */
-static int alc_auto_fill_multi_ios(struct hda_codec *codec,
-                                  unsigned int location)
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc861_quirks.c"
+#endif
+
+static int patch_alc861(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int type, i, num_pins = 0;
+       struct alc_spec *spec;
+       int board_config;
+       int err;
 
-       for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
-               for (i = 0; i < cfg->num_inputs; i++) {
-                       hda_nid_t nid = cfg->inputs[i].pin;
-                       hda_nid_t dac;
-                       unsigned int defcfg, caps;
-                       if (cfg->inputs[i].type != type)
-                               continue;
-                       defcfg = snd_hda_codec_get_pincfg(codec, nid);
-                       if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
-                               continue;
-                       if (location && get_defcfg_location(defcfg) != location)
-                               continue;
-                       caps = snd_hda_query_pin_caps(codec, nid);
-                       if (!(caps & AC_PINCAP_OUT))
-                               continue;
-                       dac = alc_auto_look_for_dac(codec, nid);
-                       if (!dac)
-                               continue;
-                       spec->multi_io[num_pins].pin = nid;
-                       spec->multi_io[num_pins].dac = dac;
-                       num_pins++;
-                       spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       spec->mixer_nid = 0x15;
+
+        board_config = alc_board_config(codec, ALC861_MODEL_LAST,
+                                       alc861_models, alc861_cfg_tbl);
+
+       if (board_config < 0) {
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
+               board_config = ALC_MODEL_AUTO;
+       }
+
+       if (board_config == ALC_MODEL_AUTO) {
+               alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
+               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+       }
+
+       if (board_config == ALC_MODEL_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc861_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                  board_config = ALC861_3ST_DIG;
                }
+#endif
        }
-       spec->multiout.num_dacs = 1;
-       if (num_pins < 2)
-               return 0;
-       return num_pins;
-}
 
-static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
+       if (board_config != ALC_MODEL_AUTO)
+               setup_preset(codec, &alc861_presets[board_config]);
 
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = spec->multi_ios + 1;
-       if (uinfo->value.enumerated.item > spec->multi_ios)
-               uinfo->value.enumerated.item = spec->multi_ios;
-       sprintf(uinfo->value.enumerated.name, "%dch",
-               (uinfo->value.enumerated.item + 1) * 2);
-       return 0;
-}
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
+       }
 
-static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
-       return 0;
-}
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
 
-static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t nid = spec->multi_io[idx].pin;
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x23);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+       }
 
-       if (!spec->multi_io[idx].ctl_in)
-               spec->multi_io[idx].ctl_in =
-                       snd_hda_codec_read(codec, nid, 0,
-                                          AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-       if (output) {
-               snd_hda_codec_update_cache(codec, nid, 0,
-                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                          PIN_OUT);
-               if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
-                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE, 0);
-               alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
-       } else {
-               if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
-                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE, HDA_AMP_MUTE);
-               snd_hda_codec_update_cache(codec, nid, 0,
-                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                          spec->multi_io[idx].ctl_in);
+       spec->vmaster_nid = 0x03;
+
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
+
+       codec->patch_ops = alc_patch_ops;
+       if (board_config == ALC_MODEL_AUTO) {
+               spec->init_hook = alc_auto_init_std;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+               spec->power_hook = alc_power_eapd;
+#endif
        }
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       if (!spec->loopback.amplist)
+               spec->loopback.amplist = alc861_loopbacks;
+#endif
+
        return 0;
 }
 
-static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       int i, ch;
+/*
+ * ALC861-VD support
+ *
+ * Based on ALC882
+ *
+ * In addition, an independent DAC
+ */
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+#define alc861vd_loopbacks     alc880_loopbacks
+#endif
 
-       ch = ucontrol->value.enumerated.item[0];
-       if (ch < 0 || ch > spec->multi_ios)
-               return -EINVAL;
-       if (ch == (spec->ext_channel_count - 1) / 2)
-               return 0;
-       spec->ext_channel_count = (ch + 1) * 2;
-       for (i = 0; i < spec->multi_ios; i++)
-               alc_set_multi_io(codec, i, i < ch);
-       spec->multiout.max_channels = spec->ext_channel_count;
-       return 1;
+static int alc861vd_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
 }
 
-static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Channel Mode",
-       .info = alc_auto_ch_mode_info,
-       .get = alc_auto_ch_mode_get,
-       .put = alc_auto_ch_mode_put,
+enum {
+       ALC660VD_FIX_ASUS_GPIO1
+};
+
+/* reset GPIO1 */
+static const struct alc_fixup alc861vd_fixups[] = {
+       [ALC660VD_FIX_ASUS_GPIO1] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+                       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+                       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+                       { }
+               }
+       },
+};
+
+static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
+       {}
 };
 
-static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
+static const struct hda_verb alc660vd_eapd_verbs[] = {
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+/*
+ */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc861vd_quirks.c"
+#endif
+
+static int patch_alc861vd(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int location, defcfg;
-       int num_pins;
+       struct alc_spec *spec;
+       int err, board_config;
 
-       if (cfg->line_outs != 1 ||
-           cfg->line_out_type != AUTO_PIN_LINE_OUT)
-               return 0;
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
 
-       defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
-       location = get_defcfg_location(defcfg);
+       codec->spec = spec;
 
-       num_pins = alc_auto_fill_multi_ios(codec, location);
-       if (num_pins > 0) {
-               struct snd_kcontrol_new *knew;
+       spec->mixer_nid = 0x0b;
 
-               knew = alc_kcontrol_new(spec);
-               if (!knew)
-                       return -ENOMEM;
-               *knew = alc_auto_channel_mode_enum;
-               knew->name = kstrdup("Channel Mode", GFP_KERNEL);
-               if (!knew->name)
-                       return -ENOMEM;
+       board_config = alc_board_config(codec, ALC861VD_MODEL_LAST,
+                                       alc861vd_models, alc861vd_cfg_tbl);
 
-               spec->multi_ios = num_pins;
-               spec->ext_channel_count = 2;
-               spec->multiout.num_dacs = num_pins + 1;
+       if (board_config < 0) {
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
+               board_config = ALC_MODEL_AUTO;
        }
-       return 0;
-}
 
-static int alc662_parse_auto_config(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
+       if (board_config == ALC_MODEL_AUTO) {
+               alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
+               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+       }
 
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc662_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs)
-               return 0; /* can't find valid BIOS pin config */
+       if (board_config == ALC_MODEL_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc861vd_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                       board_config = ALC861VD_3ST;
+               }
+#endif
+       }
 
-       err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_add_multi_channel_mode(codec);
-       if (err < 0)
-               return err;
-       err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc662_auto_create_extra_out(codec,
-                                          spec->autocfg.speaker_pins[0],
-                                          "Speaker");
-       if (err < 0)
-               return err;
-       if (err)
-               spec->multiout.extra_out_nid[0] = err;
-       err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
-                                          "Headphone");
-       if (err < 0)
-               return err;
-       if (err)
-               spec->multiout.hp_nid = err;
-       err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
+       if (board_config != ALC_MODEL_AUTO)
+               setup_preset(codec, &alc861vd_presets[board_config]);
 
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+       if (codec->vendor_id == 0x10ec0660) {
+               /* always turn on EAPD */
+               add_verb(spec, alc660vd_eapd_verbs);
+       }
 
-       alc_auto_parse_digital(codec);
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
+       }
 
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
+
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x23);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       }
+
+       spec->vmaster_nid = 0x02;
+
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
+
+       codec->patch_ops = alc_patch_ops;
+
+       if (board_config == ALC_MODEL_AUTO)
+               spec->init_hook = alc_auto_init_std;
+       spec->shutup = alc_eapd_shutup;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       if (!spec->loopback.amplist)
+               spec->loopback.amplist = alc861vd_loopbacks;
+#endif
+
+       return 0;
+}
+
+/*
+ * ALC662 support
+ *
+ * ALC662 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration.  Each pin widget can choose any input DACs and a mixer.
+ * Each ADC is connected from a mixer of all inputs.  This makes possible
+ * 6-channel independent captures.
+ *
+ * In addition, an independent DAC for the multi-playback (not used in this
+ * driver yet).
+ */
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+#define alc662_loopbacks       alc880_loopbacks
+#endif
 
-       spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux[0];
+/*
+ * BIOS auto configuration
+ */
 
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
+static int alc662_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
+       static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       const hda_nid_t *ssids;
 
        if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
            codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
-           alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
+               ssids = alc663_ssids;
        else
-           alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
-       return 1;
-}
-
-/* additional initialization for auto-configuration model */
-static void alc662_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc662_auto_init_multi_out(codec);
-       alc662_auto_init_hp_out(codec);
-       alc662_auto_init_analog_input(codec);
-       alc662_auto_init_input_src(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
+               ssids = alc662_ssids;
+       return alc_parse_auto_config(codec, alc662_ignore, ssids);
 }
 
 static void alc272_fixup_mario(struct hda_codec *codec,
@@ -19459,6 +5070,7 @@ enum {
        ALC272_FIXUP_MARIO,
        ALC662_FIXUP_CZC_P10T,
        ALC662_FIXUP_SKU_IGNORE,
+       ALC662_FIXUP_HP_RP5800,
 };
 
 static const struct alc_fixup alc662_fixups[] = {
@@ -19491,12 +5103,22 @@ static const struct alc_fixup alc662_fixups[] = {
                .type = ALC_FIXUP_SKU,
                .v.sku = ALC_FIXUP_SKU_IGNORE,
        },
+       [ALC662_FIXUP_HP_RP5800] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x0221201f }, /* HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+       SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
@@ -19510,6 +5132,12 @@ static const struct alc_model_fixup alc662_fixup_models[] = {
 };
 
 
+/*
+ */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc662_quirks.c"
+#endif
+
 static int patch_alc662(struct hda_codec *codec)
 {
        struct alc_spec *spec;
@@ -19522,6 +5150,8 @@ static int patch_alc662(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       spec->mixer_nid = 0x0b;
+
        alc_auto_parse_customize_define(codec);
 
        alc_fix_pll_init(codec, 0x20, 0x04, 15);
@@ -19536,16 +5166,15 @@ static int patch_alc662(struct hda_codec *codec)
        else if (coef == 0x4011)
                alc_codec_rename(codec, "ALC656");
 
-       board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
-                                                 alc662_models,
-                                                 alc662_cfg_tbl);
+       board_config = alc_board_config(codec, ALC662_MODEL_LAST,
+                                       alc662_models, alc662_cfg_tbl);
        if (board_config < 0) {
                printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
                       codec->chip_name);
-               board_config = ALC662_AUTO;
+               board_config = ALC_MODEL_AUTO;
        }
 
-       if (board_config == ALC662_AUTO) {
+       if (board_config == ALC_MODEL_AUTO) {
                alc_pick_fixup(codec, alc662_fixup_models,
                               alc662_fixup_tbl, alc662_fixups);
                alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -19554,42 +5183,35 @@ static int patch_alc662(struct hda_codec *codec)
                if (err < 0) {
                        alc_free(codec);
                        return err;
-               } else if (!err) {
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
                        printk(KERN_INFO
                               "hda_codec: Cannot set up configuration "
                               "from BIOS.  Using base mode...\n");
                        board_config = ALC662_3ST_2ch_DIG;
                }
+#endif
        }
 
-       if (has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               }
-       }
-
-       if (board_config != ALC662_AUTO)
+       if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc662_presets[board_config]);
 
-       spec->stream_analog_playback = &alc662_pcm_analog_playback;
-       spec->stream_analog_capture = &alc662_pcm_analog_capture;
-
-       spec->stream_digital_playback = &alc662_pcm_digital_playback;
-       spec->stream_digital_capture = &alc662_pcm_digital_capture;
-
-       if (!spec->adc_nids) {
-               spec->adc_nids = alc662_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
        }
-       if (!spec->capsrc_nids)
-               spec->capsrc_nids = alc662_capsrc_nids;
 
-       if (!spec->cap_mixer)
+       if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
 
-       if (has_cdefine_beep(codec)) {
+       if (!spec->no_analog && has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
                switch (codec->vendor_id) {
                case 0x10ec0662:
                        set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
@@ -19609,8 +5231,8 @@ static int patch_alc662(struct hda_codec *codec)
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC662_AUTO)
-               spec->init_hook = alc662_auto_init;
+       if (board_config == ALC_MODEL_AUTO)
+               spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
        alc_init_jacks(codec);
@@ -19652,389 +5274,17 @@ static int patch_alc899(struct hda_codec *codec)
 /*
  * ALC680 support
  */
-#define ALC680_DIGIN_NID       ALC880_DIGIN_NID
-#define ALC680_DIGOUT_NID      ALC880_DIGOUT_NID
-#define alc680_modes           alc260_modes
-
-static const hda_nid_t alc680_dac_nids[3] = {
-       /* Lout1, Lout2, hp */
-       0x02, 0x03, 0x04
-};
-
-static const hda_nid_t alc680_adc_nids[3] = {
-       /* ADC0-2 */
-       /* DMIC, MIC, Line-in*/
-       0x07, 0x08, 0x09
-};
-
-/*
- * Analog capture ADC cgange
- */
-static void alc680_rec_autoswitch(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int pin_found = 0;
-       int type_found = AUTO_PIN_LAST;
-       hda_nid_t nid;
-       int i;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               nid = cfg->inputs[i].pin;
-               if (!is_jack_detectable(codec, nid))
-                       continue;
-               if (snd_hda_jack_detect(codec, nid)) {
-                       if (cfg->inputs[i].type < type_found) {
-                               type_found = cfg->inputs[i].type;
-                               pin_found = nid;
-                       }
-               }
-       }
-
-       nid = 0x07;
-       if (pin_found)
-               snd_hda_get_connections(codec, pin_found, &nid, 1);
-
-       if (nid != spec->cur_adc)
-               __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
-       spec->cur_adc = nid;
-       snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
-                                  spec->cur_adc_format);
-}
-
-static int alc680_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 alc_spec *spec = codec->spec;
-
-       spec->cur_adc = 0x07;
-       spec->cur_adc_stream_tag = stream_tag;
-       spec->cur_adc_format = format;
-
-       alc680_rec_autoswitch(codec);
-       return 0;
-}
-
-static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                     struct hda_codec *codec,
-                                     struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_cleanup_stream(codec, 0x07);
-       snd_hda_codec_cleanup_stream(codec, 0x08);
-       snd_hda_codec_cleanup_stream(codec, 0x09);
-       return 0;
-}
-
-static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
-       .substreams = 1, /* can be overridden */
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in alc_build_pcms */
-       .ops = {
-               .prepare = alc680_capture_pcm_prepare,
-               .cleanup = alc680_capture_pcm_cleanup
-       },
-};
-
-static const struct snd_kcontrol_new alc680_base_mixer[] = {
-       /* output mixer control */
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
-       { }
-};
-
-static const struct hda_bind_ctls alc680_bind_cap_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
-               0
-       },
-};
-
-static const struct hda_bind_ctls alc680_bind_cap_switch = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
-               0
-       },
-};
-
-static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
-       HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
-       HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
-       { } /* end */
-};
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc680_init_verbs[] = {
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT   | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
-       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
-
-       { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc680_base_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x16;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x15;
-       spec->autocfg.num_inputs = 2;
-       spec->autocfg.inputs[0].pin = 0x18;
-       spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
-       spec->autocfg.inputs[1].pin = 0x19;
-       spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
-       spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc680_unsol_event(struct hda_codec *codec,
-                                          unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc_hp_automute(codec);
-       if ((res >> 26) == ALC880_MIC_EVENT)
-               alc680_rec_autoswitch(codec);
-}
-
-static void alc680_inithook(struct hda_codec *codec)
-{
-       alc_hp_automute(codec);
-       alc680_rec_autoswitch(codec);
-}
-
-/* create input playback/capture controls for the given pin */
-static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
-                                   const char *ctlname, int idx)
-{
-       hda_nid_t dac;
-       int err;
-
-       switch (nid) {
-       case 0x14:
-               dac = 0x02;
-               break;
-       case 0x15:
-               dac = 0x03;
-               break;
-       case 0x16:
-               dac = 0x04;
-               break;
-       default:
-               return 0;
-       }
-       if (spec->multiout.dac_nids[0] != dac &&
-           spec->multiout.dac_nids[1] != dac) {
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
-                                 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
-                                                     HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
-                         HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
-
-               if (err < 0)
-                       return err;
-               spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
-       }
-
-       return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid;
-       int err;
-
-       spec->multiout.dac_nids = spec->private_dac_nids;
-
-       nid = cfg->line_out_pins[0];
-       if (nid) {
-               const char *name;
-               if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                       name = "Speaker";
-               else
-                       name = "Front";
-               err = alc680_new_analog_output(spec, nid, name, 0);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->speaker_pins[0];
-       if (nid) {
-               err = alc680_new_analog_output(spec, nid, "Speaker", 0);
-               if (err < 0)
-                       return err;
-       }
-       nid = cfg->hp_pins[0];
-       if (nid) {
-               err = alc680_new_analog_output(spec, nid, "Headphone", 0);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type)
-{
-       alc_set_pin_output(codec, nid, pin_type);
-}
-
-static void alc680_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t nid = spec->autocfg.line_out_pins[0];
-       if (nid) {
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               alc680_auto_set_output_and_unmute(codec, nid, pin_type);
-       }
-}
-
-static void alc680_auto_init_hp_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t pin;
 
-       pin = spec->autocfg.hp_pins[0];
-       if (pin)
-               alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin)
-               alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
-}
-
-/* pcm configuration: identical with ALC880 */
-#define alc680_pcm_analog_playback     alc880_pcm_analog_playback
-#define alc680_pcm_analog_capture      alc880_pcm_analog_capture
-#define alc680_pcm_analog_alt_capture  alc880_pcm_analog_alt_capture
-#define alc680_pcm_digital_playback    alc880_pcm_digital_playback
-#define alc680_pcm_digital_capture     alc880_pcm_digital_capture
-
-/*
- * BIOS auto configuration
- */
 static int alc680_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc680_ignore[] = { 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc680_ignore);
-       if (err < 0)
-               return err;
-
-       if (!spec->autocfg.line_outs) {
-               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
-                       spec->multiout.max_channels = 2;
-                       spec->no_analog = 1;
-                       goto dig_only;
-               }
-               return 0; /* can't find valid BIOS pin config */
-       }
-       err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = 2;
-
- dig_only:
-       /* digital only support output */
-       alc_auto_parse_digital(codec);
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       add_verb(spec, alc680_init_verbs);
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       return 1;
-}
-
-#define alc680_auto_init_analog_input  alc882_auto_init_analog_input
-
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc680_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc680_auto_init_multi_out(codec);
-       alc680_auto_init_hp_out(codec);
-       alc680_auto_init_analog_input(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
+       return alc_parse_auto_config(codec, NULL, NULL);
 }
 
 /*
- * configuration and preset
  */
-static const char * const alc680_models[ALC680_MODEL_LAST] = {
-       [ALC680_BASE]           = "base",
-       [ALC680_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk alc680_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
-       {}
-};
-
-static const struct alc_config_preset alc680_presets[] = {
-       [ALC680_BASE] = {
-               .mixers = { alc680_base_mixer },
-               .cap_mixer =  alc680_master_capture_mixer,
-               .init_verbs = { alc680_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc680_dac_nids),
-               .dac_nids = alc680_dac_nids,
-               .dig_out_nid = ALC680_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc680_modes),
-               .channel_mode = alc680_modes,
-               .unsol_event = alc680_unsol_event,
-               .setup = alc680_base_setup,
-               .init_hook = alc680_inithook,
-
-       },
-};
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc680_quirks.c"
+#endif
 
 static int patch_alc680(struct hda_codec *codec)
 {
@@ -20048,51 +5298,55 @@ static int patch_alc680(struct hda_codec *codec)
 
        codec->spec = spec;
 
-       board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
-                                                 alc680_models,
-                                                 alc680_cfg_tbl);
+       /* ALC680 has no aa-loopback mixer */
 
-       if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
+       board_config = alc_board_config(codec, ALC680_MODEL_LAST,
+                                       alc680_models, alc680_cfg_tbl);
+
+       if (board_config < 0) {
                printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
                       codec->chip_name);
-               board_config = ALC680_AUTO;
+               board_config = ALC_MODEL_AUTO;
        }
 
-       if (board_config == ALC680_AUTO) {
+       if (board_config == ALC_MODEL_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc680_parse_auto_config(codec);
                if (err < 0) {
                        alc_free(codec);
                        return err;
-               } else if (!err) {
+               }
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               else if (!err) {
                        printk(KERN_INFO
                               "hda_codec: Cannot set up configuration "
                               "from BIOS.  Using base mode...\n");
                        board_config = ALC680_BASE;
                }
+#endif
        }
 
-       if (board_config != ALC680_AUTO)
+       if (board_config != ALC_MODEL_AUTO) {
                setup_preset(codec, &alc680_presets[board_config]);
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+               spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
+#endif
+       }
 
-       spec->stream_analog_playback = &alc680_pcm_analog_playback;
-       spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
-       spec->stream_digital_playback = &alc680_pcm_digital_playback;
-       spec->stream_digital_capture = &alc680_pcm_digital_capture;
-
-       if (!spec->adc_nids) {
-               spec->adc_nids = alc680_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+               alc_auto_fill_adc_caps(codec);
+               alc_rebuild_imux_for_auto_mic(codec);
+               alc_remove_invalid_adc_nids(codec);
        }
 
-       if (!spec->cap_mixer)
+       if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
 
        spec->vmaster_nid = 0x02;
 
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC680_AUTO)
-               spec->init_hook = alc680_auto_init;
+       if (board_config == ALC_MODEL_AUTO)
+               spec->init_hook = alc_auto_init_std;
 
        return 0;
 }
index 7f81cc2..56425a5 100644 (file)
@@ -1112,7 +1112,9 @@ static int stac92xx_build_controls(struct hda_codec *codec)
        }
 
        if (spec->multiout.dig_out_nid) {
-               err = snd_hda_create_spdif_out_ctls(codec, 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,
@@ -3406,30 +3408,9 @@ static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux,
        return 0;
 }
 
-static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
-                               hda_nid_t nid)
-{
-       hda_nid_t conn[HDA_MAX_NUM_INPUTS];
-       int i, nums;
-
-       if (!(get_wcaps(codec, mux) & AC_WCAP_CONN_LIST))
-               return -1;
-
-       nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
-       for (i = 0; i < nums; i++)
-               if (conn[i] == nid)
-                       return i;
-
-       for (i = 0; i < nums; i++) {
-               unsigned int wid_caps = get_wcaps(codec, conn[i]);
-               unsigned int wid_type = get_wcaps_type(wid_caps);
-
-               if (wid_type != AC_WID_PIN && wid_type != AC_WID_AUD_MIX)
-                       if (get_connection_index(codec, conn[i], nid) >= 0)
-                               return i;
-       }
-       return -1;
-}
+/* look for NID recursively */
+#define get_connection_index(codec, mux, nid) \
+       snd_hda_get_conn_index(codec, mux, nid, 1)
 
 /* create a volume assigned to the given pin (only if supported) */
 /* return 1 if the volume control is created */
index f43bb0e..f38160b 100644 (file)
 #include "hda_codec.h"
 #include "hda_local.h"
 
-#define NID_MAPPING            (-1)
-
-/* amp values */
-#define AMP_VAL_IDX_SHIFT      19
-#define AMP_VAL_IDX_MASK       (0x0f<<19)
-
 /* Pin Widget NID */
-#define VT1708_HP_NID          0x13
-#define VT1708_DIGOUT_NID      0x14
-#define VT1708_DIGIN_NID       0x16
-#define VT1708_DIGIN_PIN       0x26
 #define VT1708_HP_PIN_NID      0x20
 #define VT1708_CD_PIN_NID      0x24
 
-#define VT1709_HP_DAC_NID      0x28
-#define VT1709_DIGOUT_NID      0x13
-#define VT1709_DIGIN_NID       0x17
-#define VT1709_DIGIN_PIN       0x25
-
-#define VT1708B_HP_NID         0x25
-#define VT1708B_DIGOUT_NID     0x12
-#define VT1708B_DIGIN_NID      0x15
-#define VT1708B_DIGIN_PIN      0x21
-
-#define VT1708S_HP_NID         0x25
-#define VT1708S_DIGOUT_NID     0x12
-
-#define VT1702_HP_NID          0x17
-#define VT1702_DIGOUT_NID      0x11
-
 enum VIA_HDA_CODEC {
        UNKNOWN = -1,
        VT1708,
@@ -107,6 +81,39 @@ enum VIA_HDA_CODEC {
         (spec)->codec_type == VT1812 ||\
         (spec)->codec_type == VT1802)
 
+#define MAX_NID_PATH_DEPTH     5
+
+/* output-path: DAC -> ... -> pin
+ * idx[] contains the source index number of the next widget;
+ * e.g. idx[0] is the index of the DAC selected by path[1] widget
+ * multi[] indicates whether it's a selector widget with multi-connectors
+ * (i.e. the connection selection is mandatory)
+ * vol_ctl and mute_ctl contains the NIDs for the assigned mixers
+ */
+struct nid_path {
+       int depth;
+       hda_nid_t path[MAX_NID_PATH_DEPTH];
+       unsigned char idx[MAX_NID_PATH_DEPTH];
+       unsigned char multi[MAX_NID_PATH_DEPTH];
+       unsigned int vol_ctl;
+       unsigned int mute_ctl;
+};
+
+/* input-path */
+struct via_input {
+       hda_nid_t pin;  /* input-pin or aa-mix */
+       int adc_idx;    /* ADC index to be used */
+       int mux_idx;    /* MUX index (if any) */
+       const char *label;      /* input-source label */
+};
+
+#define VIA_MAX_ADCS   3
+
+enum {
+       STREAM_MULTI_OUT = (1 << 0),
+       STREAM_INDEP_HP = (1 << 1),
+};
+
 struct via_spec {
        /* codec parameterization */
        const struct snd_kcontrol_new *mixers[6];
@@ -115,28 +122,66 @@ struct via_spec {
        const struct hda_verb *init_verbs[5];
        unsigned int num_iverbs;
 
-       char *stream_name_analog;
+       char stream_name_analog[32];
+       char stream_name_hp[32];
        const struct hda_pcm_stream *stream_analog_playback;
        const struct hda_pcm_stream *stream_analog_capture;
 
-       char *stream_name_digital;
+       char stream_name_digital[32];
        const struct hda_pcm_stream *stream_digital_playback;
        const struct hda_pcm_stream *stream_digital_capture;
 
        /* playback */
        struct hda_multi_out multiout;
        hda_nid_t slave_dig_outs[2];
+       hda_nid_t hp_dac_nid;
+       hda_nid_t speaker_dac_nid;
+       int hp_indep_shared;    /* indep HP-DAC is shared with side ch */
+       int opened_streams;     /* STREAM_* bits */
+       int active_streams;     /* STREAM_* bits */
+       int aamix_mode;         /* loopback is enabled for output-path? */
+
+       /* Output-paths:
+        * There are different output-paths depending on the setup.
+        * out_path, hp_path and speaker_path are primary paths.  If both
+        * direct DAC and aa-loopback routes are available, these contain
+        * the former paths.  Meanwhile *_mix_path contain the paths with
+        * loopback mixer.  (Since the loopback is only for front channel,
+        * no out_mix_path for surround channels.)
+        * The HP output has another path, hp_indep_path, which is used in
+        * the independent-HP mode.
+        */
+       struct nid_path out_path[HDA_SIDE + 1];
+       struct nid_path out_mix_path;
+       struct nid_path hp_path;
+       struct nid_path hp_mix_path;
+       struct nid_path hp_indep_path;
+       struct nid_path speaker_path;
+       struct nid_path speaker_mix_path;
 
        /* capture */
        unsigned int num_adc_nids;
-       const hda_nid_t *adc_nids;
-       hda_nid_t mux_nids[3];
+       hda_nid_t adc_nids[VIA_MAX_ADCS];
+       hda_nid_t mux_nids[VIA_MAX_ADCS];
+       hda_nid_t aa_mix_nid;
        hda_nid_t dig_in_nid;
-       hda_nid_t dig_in_pin;
 
        /* capture source */
-       const struct hda_input_mux *input_mux;
-       unsigned int cur_mux[3];
+       bool dyn_adc_switch;
+       int num_inputs;
+       struct via_input inputs[AUTO_CFG_MAX_INS + 1];
+       unsigned int cur_mux[VIA_MAX_ADCS];
+
+       /* dynamic DAC switching */
+       unsigned int cur_dac_stream_tag;
+       unsigned int cur_dac_format;
+       unsigned int cur_hp_stream_tag;
+       unsigned int cur_hp_format;
+
+       /* dynamic ADC switching */
+       hda_nid_t cur_adc;
+       unsigned int cur_adc_stream_tag;
+       unsigned int cur_adc_format;
 
        /* PCM information */
        struct hda_pcm pcm_rec[3];
@@ -144,28 +189,38 @@ struct via_spec {
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
        struct snd_array kctls;
-       struct hda_input_mux private_imux[2];
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
        /* HP mode source */
-       const struct hda_input_mux *hp_mux;
        unsigned int hp_independent_mode;
-       unsigned int hp_independent_mode_index;
-       unsigned int smart51_enabled;
        unsigned int dmic_enabled;
+       unsigned int no_pin_power_ctl;
        enum VIA_HDA_CODEC codec_type;
 
+       /* smart51 setup */
+       unsigned int smart51_nums;
+       hda_nid_t smart51_pins[2];
+       int smart51_idxs[2];
+       const char *smart51_labels[2];
+       unsigned int smart51_enabled;
+
        /* work to check hp jack state */
        struct hda_codec *codec;
        struct delayed_work vt1708_hp_work;
-       int vt1708_jack_detectect;
+       int vt1708_jack_detect;
        int vt1708_hp_present;
 
        void (*set_widgets_power_state)(struct hda_codec *codec);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
-#endif
+       int num_loopbacks;
+       struct hda_amp_list loopback_list[8];
+
+       /* bind capture-volume */
+       struct hda_bind_ctls *bind_cap_vol;
+       struct hda_bind_ctls *bind_cap_sw;
+
+       struct mutex config_mutex;
 };
 
 static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
@@ -177,6 +232,7 @@ static struct via_spec * via_new_spec(struct hda_codec *codec)
        if (spec == NULL)
                return NULL;
 
+       mutex_init(&spec->config_mutex);
        codec->spec = spec;
        spec->codec = codec;
        spec->codec_type = get_codec_type(codec);
@@ -237,33 +293,23 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
 #define VIA_JACK_EVENT         0x20
 #define VIA_HP_EVENT           0x01
 #define VIA_GPIO_EVENT         0x02
-#define VIA_MONO_EVENT         0x03
-#define VIA_SPEAKER_EVENT      0x04
-#define VIA_BIND_HP_EVENT      0x05
+#define VIA_LINE_EVENT         0x03
 
 enum {
        VIA_CTL_WIDGET_VOL,
        VIA_CTL_WIDGET_MUTE,
        VIA_CTL_WIDGET_ANALOG_MUTE,
-       VIA_CTL_WIDGET_BIND_PIN_MUTE,
 };
 
-enum {
-       AUTO_SEQ_FRONT = 0,
-       AUTO_SEQ_SURROUND,
-       AUTO_SEQ_CENLFE,
-       AUTO_SEQ_SIDE
-};
-
-static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
-static int is_aa_path_mute(struct hda_codec *codec);
+static void analog_low_current_mode(struct hda_codec *codec);
+static bool is_aa_path_mute(struct hda_codec *codec);
 
 static void vt1708_start_hp_work(struct via_spec *spec)
 {
        if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
                return;
        snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
-                           !spec->vt1708_jack_detectect);
+                           !spec->vt1708_jack_detect);
        if (!delayed_work_pending(&spec->vt1708_hp_work))
                schedule_delayed_work(&spec->vt1708_hp_work,
                                      msecs_to_jiffies(100));
@@ -277,7 +323,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec)
            && !is_aa_path_mute(spec->codec))
                return;
        snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
-                           !spec->vt1708_jack_detectect);
+                           !spec->vt1708_jack_detect);
        cancel_delayed_work_sync(&spec->vt1708_hp_work);
 }
 
@@ -295,7 +341,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 
        set_widgets_power_state(codec);
-       analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
+       analog_low_current_mode(snd_kcontrol_chip(kcontrol));
        if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
                if (is_aa_path_mute(codec))
                        vt1708_start_hp_work(codec->spec);
@@ -315,168 +361,44 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
                        .put = analog_input_switch_put,                 \
                        .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
 
-static void via_hp_bind_automute(struct hda_codec *codec);
-
-static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-       int i;
-       int change = 0;
-
-       long *valp = ucontrol->value.integer.value;
-       int lmute, rmute;
-       if (strstr(kcontrol->id.name, "Switch") == NULL) {
-               snd_printd("Invalid control!\n");
-               return change;
-       }
-       change = snd_hda_mixer_amp_switch_put(kcontrol,
-                                             ucontrol);
-       /* Get mute value */
-       lmute = *valp ? 0 : HDA_AMP_MUTE;
-       valp++;
-       rmute = *valp ? 0 : HDA_AMP_MUTE;
-
-       /* Set hp pins */
-       if (!spec->hp_independent_mode) {
-               for (i = 0; i < spec->autocfg.hp_outs; i++) {
-                       snd_hda_codec_amp_update(
-                               codec, spec->autocfg.hp_pins[i],
-                               0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                               lmute);
-                       snd_hda_codec_amp_update(
-                               codec, spec->autocfg.hp_pins[i],
-                               1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                               rmute);
-               }
-       }
-
-       if (!lmute && !rmute) {
-               /* Line Outs */
-               for (i = 0; i < spec->autocfg.line_outs; i++)
-                       snd_hda_codec_amp_stereo(
-                               codec, spec->autocfg.line_out_pins[i],
-                               HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
-               /* Speakers */
-               for (i = 0; i < spec->autocfg.speaker_outs; i++)
-                       snd_hda_codec_amp_stereo(
-                               codec, spec->autocfg.speaker_pins[i],
-                               HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
-               /* unmute */
-               via_hp_bind_automute(codec);
-
-       } else {
-               if (lmute) {
-                       /* Mute all left channels */
-                       for (i = 1; i < spec->autocfg.line_outs; i++)
-                               snd_hda_codec_amp_update(
-                                       codec,
-                                       spec->autocfg.line_out_pins[i],
-                                       0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                                       lmute);
-                       for (i = 0; i < spec->autocfg.speaker_outs; i++)
-                               snd_hda_codec_amp_update(
-                                       codec,
-                                       spec->autocfg.speaker_pins[i],
-                                       0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                                       lmute);
-               }
-               if (rmute) {
-                       /* mute all right channels */
-                       for (i = 1; i < spec->autocfg.line_outs; i++)
-                               snd_hda_codec_amp_update(
-                                       codec,
-                                       spec->autocfg.line_out_pins[i],
-                                       1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                                       rmute);
-                       for (i = 0; i < spec->autocfg.speaker_outs; i++)
-                               snd_hda_codec_amp_update(
-                                       codec,
-                                       spec->autocfg.speaker_pins[i],
-                                       1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                                       rmute);
-               }
-       }
-       return change;
-}
-
-#define BIND_PIN_MUTE                                                  \
-       {               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
-                       .name = NULL,                                   \
-                       .index = 0,                                     \
-                       .info = snd_hda_mixer_amp_switch_info,          \
-                       .get = snd_hda_mixer_amp_switch_get,            \
-                       .put = bind_pin_switch_put,                     \
-                       .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
-
 static const struct snd_kcontrol_new via_control_templates[] = {
        HDA_CODEC_VOLUME(NULL, 0, 0, 0),
        HDA_CODEC_MUTE(NULL, 0, 0, 0),
        ANALOG_INPUT_MUTE,
-       BIND_PIN_MUTE,
-};
-
-static const hda_nid_t vt1708_adc_nids[2] = {
-       /* ADC1-2 */
-       0x15, 0x27
-};
-
-static const hda_nid_t vt1709_adc_nids[3] = {
-       /* ADC1-2 */
-       0x14, 0x15, 0x16
-};
-
-static const hda_nid_t vt1708B_adc_nids[2] = {
-       /* ADC1-2 */
-       0x13, 0x14
-};
-
-static const hda_nid_t vt1708S_adc_nids[2] = {
-       /* ADC1-2 */
-       0x13, 0x14
-};
-
-static const hda_nid_t vt1702_adc_nids[3] = {
-       /* ADC1-2 */
-       0x12, 0x20, 0x1F
-};
-
-static const hda_nid_t vt1718S_adc_nids[2] = {
-       /* ADC1-2 */
-       0x10, 0x11
-};
-
-static const hda_nid_t vt1716S_adc_nids[2] = {
-       /* ADC1-2 */
-       0x13, 0x14
 };
 
-static const hda_nid_t vt2002P_adc_nids[2] = {
-       /* ADC1-2 */
-       0x10, 0x11
-};
 
-static const hda_nid_t vt1812_adc_nids[2] = {
-       /* ADC1-2 */
-       0x10, 0x11
-};
+/* add dynamic controls */
+static struct snd_kcontrol_new *__via_clone_ctl(struct via_spec *spec,
+                               const struct snd_kcontrol_new *tmpl,
+                               const char *name)
+{
+       struct snd_kcontrol_new *knew;
 
+       snd_array_init(&spec->kctls, sizeof(*knew), 32);
+       knew = snd_array_new(&spec->kctls);
+       if (!knew)
+               return NULL;
+       *knew = *tmpl;
+       if (!name)
+               name = tmpl->name;
+       if (name) {
+               knew->name = kstrdup(name, GFP_KERNEL);
+               if (!knew->name)
+                       return NULL;
+       }
+       return knew;
+}
 
-/* add dynamic controls */
 static int __via_add_control(struct via_spec *spec, int type, const char *name,
                             int idx, unsigned long val)
 {
        struct snd_kcontrol_new *knew;
 
-       snd_array_init(&spec->kctls, sizeof(*knew), 32);
-       knew = snd_array_new(&spec->kctls);
+       knew = __via_clone_ctl(spec, &via_control_templates[type], name);
        if (!knew)
                return -ENOMEM;
-       *knew = via_control_templates[type];
-       knew->name = kstrdup(name, GFP_KERNEL);
-       if (!knew->name)
-               return -ENOMEM;
+       knew->index = idx;
        if (get_amp_nid_(val))
                knew->subdevice = HDA_SUBDEV_AMP_FLAG;
        knew->private_value = val;
@@ -486,21 +408,7 @@ static int __via_add_control(struct via_spec *spec, int type, const char *name,
 #define via_add_control(spec, type, name, val) \
        __via_add_control(spec, type, name, 0, val)
 
-static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
-                               const struct snd_kcontrol_new *tmpl)
-{
-       struct snd_kcontrol_new *knew;
-
-       snd_array_init(&spec->kctls, sizeof(*knew), 32);
-       knew = snd_array_new(&spec->kctls);
-       if (!knew)
-               return NULL;
-       *knew = *tmpl;
-       knew->name = kstrdup(tmpl->name, GFP_KERNEL);
-       if (!knew->name)
-               return NULL;
-       return knew;
-}
+#define via_clone_control(spec, tmpl) __via_clone_ctl(spec, tmpl, NULL)
 
 static void via_free_kctls(struct hda_codec *codec)
 {
@@ -535,58 +443,208 @@ static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
        return 0;
 }
 
-static void via_auto_set_output_and_unmute(struct hda_codec *codec,
-                                          hda_nid_t nid, int pin_type,
-                                          int dac_idx)
+#define get_connection_index(codec, mux, nid) \
+       snd_hda_get_conn_index(codec, mux, nid, 0)
+
+static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
+                          unsigned int mask)
+{
+       unsigned int caps;
+       if (!nid)
+               return false;
+       caps = get_wcaps(codec, nid);
+       if (dir == HDA_INPUT)
+               caps &= AC_WCAP_IN_AMP;
+       else
+               caps &= AC_WCAP_OUT_AMP;
+       if (!caps)
+               return false;
+       if (query_amp_caps(codec, nid, dir) & mask)
+               return true;
+       return false;
+}
+
+#define have_mute(codec, nid, dir) \
+       check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
+
+/* enable/disable the output-route mixers */
+static void activate_output_mix(struct hda_codec *codec, struct nid_path *path,
+                               hda_nid_t mix_nid, int idx, bool enable)
+{
+       int i, num, val;
+
+       if (!path)
+               return;
+       num = snd_hda_get_conn_list(codec, mix_nid, NULL);
+       for (i = 0; i < num; i++) {
+               if (i == idx)
+                       val = AMP_IN_UNMUTE(i);
+               else
+                       val = AMP_IN_MUTE(i);
+               snd_hda_codec_write(codec, mix_nid, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, val);
+       }
+}
+
+/* enable/disable the output-route */
+static void activate_output_path(struct hda_codec *codec, struct nid_path *path,
+                                bool enable, bool force)
+{
+       struct via_spec *spec = codec->spec;
+       int i;
+       for (i = 0; i < path->depth; i++) {
+               hda_nid_t src, dst;
+               int idx = path->idx[i];
+               src = path->path[i];                    
+               if (i < path->depth - 1)
+                       dst = path->path[i + 1];
+               else
+                       dst = 0;
+               if (enable && path->multi[i])
+                       snd_hda_codec_write(codec, dst, 0,
+                                           AC_VERB_SET_CONNECT_SEL, idx);
+               if (!force && (dst == spec->aa_mix_nid))
+                       continue;
+               if (have_mute(codec, dst, HDA_INPUT))
+                       activate_output_mix(codec, path, dst, idx, enable);
+               if (!force && (src == path->vol_ctl || src == path->mute_ctl))
+                       continue;
+               if (have_mute(codec, src, HDA_OUTPUT)) {
+                       int val = enable ? AMP_OUT_UNMUTE : AMP_OUT_MUTE;
+                       snd_hda_codec_write(codec, src, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE, val);
+               }
+       }
+}
+
+/* set the given pin as output */
+static void init_output_pin(struct hda_codec *codec, hda_nid_t pin,
+                           int pin_type)
 {
-       /* set as output */
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+       if (!pin)
+               return;
+       snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                            pin_type);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_UNMUTE);
-       if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
-               snd_hda_codec_write(codec, nid, 0,
+       if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, pin, 0,
                                    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
 }
 
+static void via_auto_init_output(struct hda_codec *codec,
+                                struct nid_path *path, int pin_type)
+{
+       unsigned int caps;
+       hda_nid_t pin;
+
+       if (!path->depth)
+               return;
+       pin = path->path[path->depth - 1];
+
+       init_output_pin(codec, pin, pin_type);
+       caps = query_amp_caps(codec, pin, HDA_OUTPUT);
+       if (caps & AC_AMPCAP_MUTE) {
+               unsigned int val;
+               val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
+               snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_OUT_MUTE | val);
+       }
+       activate_output_path(codec, path, true, true); /* force on */
+}
 
 static void via_auto_init_multi_out(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
+       struct nid_path *path;
        int i;
 
-       for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
-               hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               if (nid)
-                       via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
+       for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++) {
+               path = &spec->out_path[i];
+               if (!i && spec->aamix_mode && spec->out_mix_path.depth)
+                       path = &spec->out_mix_path;
+               via_auto_init_output(codec, path, PIN_OUT);
+       }
+}
+
+/* deactivate the inactive headphone-paths */
+static void deactivate_hp_paths(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int shared = spec->hp_indep_shared;
+
+       if (spec->hp_independent_mode) {
+               activate_output_path(codec, &spec->hp_path, false, false);
+               activate_output_path(codec, &spec->hp_mix_path, false, false);
+               if (shared)
+                       activate_output_path(codec, &spec->out_path[shared],
+                                            false, false);
+       } else if (spec->aamix_mode || !spec->hp_path.depth) {
+               activate_output_path(codec, &spec->hp_indep_path, false, false);
+               activate_output_path(codec, &spec->hp_path, false, false);
+       } else {
+               activate_output_path(codec, &spec->hp_indep_path, false, false);
+               activate_output_path(codec, &spec->hp_mix_path, false, false);
        }
 }
 
 static void via_auto_init_hp_out(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
-       hda_nid_t pin;
-       int i;
 
-       for (i = 0; i < spec->autocfg.hp_outs; i++) {
-               pin = spec->autocfg.hp_pins[i];
-               if (pin) /* connect to front */
-                       via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+       if (!spec->hp_path.depth) {
+               via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP);
+               return;
+       }
+       deactivate_hp_paths(codec);
+       if (spec->hp_independent_mode)
+               via_auto_init_output(codec, &spec->hp_indep_path, PIN_HP);
+       else if (spec->aamix_mode)
+               via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP);
+       else
+               via_auto_init_output(codec, &spec->hp_path, PIN_HP);
+}
+
+static void via_auto_init_speaker_out(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+
+       if (!spec->autocfg.speaker_outs)
+               return;
+       if (!spec->speaker_path.depth) {
+               via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT);
+               return;
+       }
+       if (!spec->aamix_mode) {
+               activate_output_path(codec, &spec->speaker_mix_path,
+                                    false, false);
+               via_auto_init_output(codec, &spec->speaker_path, PIN_OUT);
+       } else {
+               activate_output_path(codec, &spec->speaker_path, false, false);
+               via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT);
        }
 }
 
-static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
+static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin);
+static void via_hp_automute(struct hda_codec *codec);
 
 static void via_auto_init_analog_input(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        const struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t conn[HDA_MAX_CONNECTIONS];
        unsigned int ctl;
-       int i;
+       int i, num_conns;
+
+       /* init ADCs */
+       for (i = 0; i < spec->num_adc_nids; i++) {
+               snd_hda_codec_write(codec, spec->adc_nids[i], 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_IN_UNMUTE(0));
+       }
 
+       /* init pins */
        for (i = 0; i < cfg->num_inputs; i++) {
                hda_nid_t nid = cfg->inputs[i].pin;
-               if (spec->smart51_enabled && is_smart51_pins(spec, nid))
+               if (spec->smart51_enabled && is_smart51_pins(codec, nid))
                        ctl = PIN_OUT;
                else if (cfg->inputs[i].type == AUTO_PIN_MIC)
                        ctl = PIN_VREF50;
@@ -595,6 +653,32 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
                snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
        }
+
+       /* init input-src */
+       for (i = 0; i < spec->num_adc_nids; i++) {
+               int adc_idx = spec->inputs[spec->cur_mux[i]].adc_idx;
+               if (spec->mux_nids[adc_idx]) {
+                       int mux_idx = spec->inputs[spec->cur_mux[i]].mux_idx;
+                       snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           mux_idx);
+               }
+               if (spec->dyn_adc_switch)
+                       break; /* only one input-src */
+       }
+
+       /* init aa-mixer */
+       if (!spec->aa_mix_nid)
+               return;
+       num_conns = snd_hda_get_connections(codec, spec->aa_mix_nid, conn,
+                                           ARRAY_SIZE(conn));
+       for (i = 0; i < num_conns; i++) {
+               unsigned int caps = get_wcaps(codec, conn[i]);
+               if (get_wcaps_type(caps) == AC_WID_PIN)
+                       snd_hda_codec_write(codec, spec->aa_mix_nid, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_IN_MUTE(i));
+       }
 }
 
 static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
@@ -605,9 +689,13 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
        unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
                >> AC_DEFCFG_MISC_SHIFT
                & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
-       unsigned present = snd_hda_jack_detect(codec, nid);
        struct via_spec *spec = codec->spec;
-       if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
+       unsigned present = 0;
+
+       no_presence |= spec->no_pin_power_ctl;
+       if (!no_presence)
+               present = snd_hda_jack_detect(codec, nid);
+       if ((spec->smart51_enabled && is_smart51_pins(codec, nid))
            || ((no_presence || present)
                && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
                *affected_parm = AC_PWRST_D0; /* if it's connected */
@@ -618,124 +706,139 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
 }
 
-/*
- * input MUX handling
- */
-static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_info *uinfo)
+static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_info *uinfo)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-       return snd_hda_input_mux_info(spec->input_mux, uinfo);
+       static const char * const texts[] = {
+               "Disabled", "Enabled"
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+       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]);
+       return 0;
 }
 
-static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
+static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_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];
+       ucontrol->value.enumerated.item[0] = !spec->no_pin_power_ctl;
        return 0;
 }
 
-static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
+static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       int ret;
-
-       if (!spec->mux_nids[adc_idx])
-               return -EINVAL;
-       /* switch to D0 beofre change index */
-       if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0,
-                              AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
-               snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
-                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+       unsigned int val = !ucontrol->value.enumerated.item[0];
 
-       ret = snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                    spec->mux_nids[adc_idx],
-                                    &spec->cur_mux[adc_idx]);
-       /* update jack power state */
+       if (val == spec->no_pin_power_ctl)
+               return 0;
+       spec->no_pin_power_ctl = val;
        set_widgets_power_state(codec);
-
-       return ret;
+       return 1;
 }
 
+static const struct snd_kcontrol_new via_pin_power_ctl_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Dynamic Power-Control",
+       .info = via_pin_power_ctl_info,
+       .get = via_pin_power_ctl_get,
+       .put = via_pin_power_ctl_put,
+};
+
+
 static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_info *uinfo)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-       return snd_hda_input_mux_info(spec->hp_mux, uinfo);
+       static const char * const texts[] = { "OFF", "ON" };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+       if (uinfo->value.enumerated.item >= 2)
+               uinfo->value.enumerated.item = 1;
+       strcpy(uinfo->value.enumerated.name,
+              texts[uinfo->value.enumerated.item]);
+       return 0;
 }
 
 static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
-       unsigned int pinsel;
-
-       /* use !! to translate conn sel 2 for VT1718S */
-       pinsel = !!snd_hda_codec_read(codec, nid, 0,
-                                     AC_VERB_GET_CONNECT_SEL,
-                                     0x00);
-       ucontrol->value.enumerated.item[0] = pinsel;
+       struct via_spec *spec = codec->spec;
 
+       ucontrol->value.enumerated.item[0] = spec->hp_independent_mode;
        return 0;
 }
 
-static void activate_ctl(struct hda_codec *codec, const char *name, int active)
-{
-       struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
-       if (ctl) {
-               ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
-               ctl->vd[0].access |= active
-                       ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE;
-               snd_ctl_notify(codec->bus->card,
-                              SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
-       }
-}
-
-static hda_nid_t side_mute_channel(struct via_spec *spec)
+/* adjust spec->multiout setup according to the current flags */
+static void setup_playback_multi_pcm(struct via_spec *spec)
 {
-       switch (spec->codec_type) {
-       case VT1708:            return 0x1b;
-       case VT1709_10CH:       return 0x29;
-       case VT1708B_8CH:       /* fall thru */
-       case VT1708S:           return 0x27;
-       case VT2002P:           return 0x19;
-       case VT1802:            return 0x15;
-       case VT1812:            return 0x15;
-       default:                return 0;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums;
+       spec->multiout.hp_nid = 0;
+       if (!spec->hp_independent_mode) {
+               if (!spec->hp_indep_shared)
+                       spec->multiout.hp_nid = spec->hp_dac_nid;
+       } else {
+               if (spec->hp_indep_shared)
+                       spec->multiout.num_dacs = cfg->line_outs - 1;
        }
 }
 
-static int update_side_mute_status(struct hda_codec *codec)
+/* update DAC setups according to indep-HP switch;
+ * this function is called only when indep-HP is modified
+ */
+static void switch_indep_hp_dacs(struct hda_codec *codec)
 {
-       /* mute side channel */
        struct via_spec *spec = codec->spec;
-       unsigned int parm;
-       hda_nid_t sw3 = side_mute_channel(spec);
+       int shared = spec->hp_indep_shared;
+       hda_nid_t shared_dac, hp_dac;
 
-       if (sw3) {
-               if (VT2002P_COMPATIBLE(spec))
-                       parm = spec->hp_independent_mode ?
-                              AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
-               else
-                       parm = spec->hp_independent_mode ?
-                              AMP_OUT_MUTE : AMP_OUT_UNMUTE;
-               snd_hda_codec_write(codec, sw3, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, parm);
-               if (spec->codec_type == VT1812)
-                       snd_hda_codec_write(codec, 0x1d, 0,
-                                           AC_VERB_SET_AMP_GAIN_MUTE, parm);
+       if (!spec->opened_streams)
+               return;
+
+       shared_dac = shared ? spec->multiout.dac_nids[shared] : 0;
+       hp_dac = spec->hp_dac_nid;
+       if (spec->hp_independent_mode) {
+               /* switch to indep-HP mode */
+               if (spec->active_streams & STREAM_MULTI_OUT) {
+                       __snd_hda_codec_cleanup_stream(codec, hp_dac, 1);
+                       __snd_hda_codec_cleanup_stream(codec, shared_dac, 1);
+               }
+               if (spec->active_streams & STREAM_INDEP_HP)
+                       snd_hda_codec_setup_stream(codec, hp_dac,
+                                                  spec->cur_hp_stream_tag, 0,
+                                                  spec->cur_hp_format);
+       } else {
+               /* back to HP or shared-DAC */
+               if (spec->active_streams & STREAM_INDEP_HP)
+                       __snd_hda_codec_cleanup_stream(codec, hp_dac, 1);
+               if (spec->active_streams & STREAM_MULTI_OUT) {
+                       hda_nid_t dac;
+                       int ch;
+                       if (shared_dac) { /* reset mutli-ch DAC */
+                               dac = shared_dac;
+                               ch = shared * 2;
+                       } else { /* reset HP DAC */
+                               dac = hp_dac;
+                               ch = 0;
+                       }
+                       snd_hda_codec_setup_stream(codec, dac,
+                                                  spec->cur_dac_stream_tag, ch,
+                                                  spec->cur_dac_format);
+               }
        }
-       return 0;
+       setup_playback_multi_pcm(spec);
 }
 
 static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
@@ -743,66 +846,46 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       hda_nid_t nid = kcontrol->private_value;
-       unsigned int pinsel = ucontrol->value.enumerated.item[0];
-       unsigned int parm0, parm1;
-       /* Get Independent Mode index of headphone pin widget */
-       spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
-               ? 1 : 0;
-       if (spec->codec_type == VT1718S) {
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0);
-               /* Set correct mute switch for MW3 */
-               parm0 = spec->hp_independent_mode ?
-                              AMP_IN_UNMUTE(0) : AMP_IN_MUTE(0);
-               parm1 = spec->hp_independent_mode ?
-                              AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
-               snd_hda_codec_write(codec, 0x1b, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, parm0);
-               snd_hda_codec_write(codec, 0x1b, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, parm1);
-       }
-       else
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_CONNECT_SEL, pinsel);
+       int cur, shared;
 
-       if (spec->codec_type == VT1812)
-               snd_hda_codec_write(codec, 0x35, 0,
-                                   AC_VERB_SET_CONNECT_SEL, pinsel);
-       if (spec->multiout.hp_nid && spec->multiout.hp_nid
-           != spec->multiout.dac_nids[HDA_FRONT])
-               snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
-                                          0, 0, 0);
-
-       update_side_mute_status(codec);
-       /* update HP volume/swtich active state */
-       if (spec->codec_type == VT1708S
-           || spec->codec_type == VT1702
-           || spec->codec_type == VT1718S
-           || spec->codec_type == VT1716S
-           || VT2002P_COMPATIBLE(spec)) {
-               activate_ctl(codec, "Headphone Playback Volume",
-                            spec->hp_independent_mode);
-               activate_ctl(codec, "Headphone Playback Switch",
-                            spec->hp_independent_mode);
+       mutex_lock(&spec->config_mutex);
+       cur = !!ucontrol->value.enumerated.item[0];
+       if (spec->hp_independent_mode == cur) {
+               mutex_unlock(&spec->config_mutex);
+               return 0;
+       }
+       spec->hp_independent_mode = cur;
+       shared = spec->hp_indep_shared;
+       deactivate_hp_paths(codec);
+       if (cur)
+               activate_output_path(codec, &spec->hp_indep_path, true, false);
+       else {
+               if (shared)
+                       activate_output_path(codec, &spec->out_path[shared],
+                                            true, false);
+               if (spec->aamix_mode || !spec->hp_path.depth)
+                       activate_output_path(codec, &spec->hp_mix_path,
+                                            true, false);
+               else
+                       activate_output_path(codec, &spec->hp_path,
+                                            true, false);
        }
+
+       switch_indep_hp_dacs(codec);
+       mutex_unlock(&spec->config_mutex);
+
        /* update jack power state */
        set_widgets_power_state(codec);
-       return 0;
+       via_hp_automute(codec);
+       return 1;
 }
 
-static const struct snd_kcontrol_new via_hp_mixer[2] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Independent HP",
-               .info = via_independent_hp_info,
-               .get = via_independent_hp_get,
-               .put = via_independent_hp_put,
-       },
-       {
-               .iface = NID_MAPPING,
-               .name = "Independent HP",
-       },
+static const struct snd_kcontrol_new via_hp_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Independent HP",
+       .info = via_independent_hp_info,
+       .get = via_independent_hp_get,
+       .put = via_independent_hp_put,
 };
 
 static int via_hp_build(struct hda_codec *codec)
@@ -810,61 +893,28 @@ static int via_hp_build(struct hda_codec *codec)
        struct via_spec *spec = codec->spec;
        struct snd_kcontrol_new *knew;
        hda_nid_t nid;
-       int nums;
-       hda_nid_t conn[HDA_MAX_CONNECTIONS];
-
-       switch (spec->codec_type) {
-       case VT1718S:
-               nid = 0x34;
-               break;
-       case VT2002P:
-       case VT1802:
-               nid = 0x35;
-               break;
-       case VT1812:
-               nid = 0x3d;
-               break;
-       default:
-               nid = spec->autocfg.hp_pins[0];
-               break;
-       }
-
-       if (spec->codec_type != VT1708) {
-               nums = snd_hda_get_connections(codec, nid,
-                                              conn, HDA_MAX_CONNECTIONS);
-               if (nums <= 1)
-                       return 0;
-       }
 
-       knew = via_clone_control(spec, &via_hp_mixer[0]);
+       nid = spec->autocfg.hp_pins[0];
+       knew = via_clone_control(spec, &via_hp_mixer);
        if (knew == NULL)
                return -ENOMEM;
 
        knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
-       knew->private_value = nid;
-
-       nid = side_mute_channel(spec);
-       if (nid) {
-               knew = via_clone_control(spec, &via_hp_mixer[1]);
-               if (knew == NULL)
-                       return -ENOMEM;
-               knew->subdevice = nid;
-       }
 
        return 0;
 }
 
 static void notify_aa_path_ctls(struct hda_codec *codec)
 {
+       struct via_spec *spec = codec->spec;
        int i;
-       struct snd_ctl_elem_id id;
-       const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"};
-       struct snd_kcontrol *ctl;
-
-       memset(&id, 0, sizeof(id));
-       id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-       for (i = 0; i < ARRAY_SIZE(labels); i++) {
-               sprintf(id.name, "%s Playback Volume", labels[i]);
+
+       for (i = 0; i < spec->smart51_nums; i++) {
+               struct snd_kcontrol *ctl;
+               struct snd_ctl_elem_id id;
+               memset(&id, 0, sizeof(id));
+               id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+               sprintf(id.name, "%s Playback Volume", spec->smart51_labels[i]);
                ctl = snd_hda_find_mixer_ctl(codec, id.name);
                if (ctl)
                        snd_ctl_notify(codec->bus->card,
@@ -876,66 +926,28 @@ static void notify_aa_path_ctls(struct hda_codec *codec)
 static void mute_aa_path(struct hda_codec *codec, int mute)
 {
        struct via_spec *spec = codec->spec;
-       hda_nid_t  nid_mixer;
-       int start_idx;
-       int end_idx;
+       int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
        int i;
-       /* get nid of MW0 and start & end index */
-       switch (spec->codec_type) {
-       case VT1708:
-               nid_mixer = 0x17;
-               start_idx = 2;
-               end_idx = 4;
-               break;
-       case VT1709_10CH:
-       case VT1709_6CH:
-               nid_mixer = 0x18;
-               start_idx = 2;
-               end_idx = 4;
-               break;
-       case VT1708B_8CH:
-       case VT1708B_4CH:
-       case VT1708S:
-       case VT1716S:
-               nid_mixer = 0x16;
-               start_idx = 2;
-               end_idx = 4;
-               break;
-       case VT1718S:
-               nid_mixer = 0x21;
-               start_idx = 1;
-               end_idx = 3;
-               break;
-       default:
-               return;
-       }
+
        /* check AA path's mute status */
-       for (i = start_idx; i <= end_idx; i++) {
-               int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
-               snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
+       for (i = 0; i < spec->smart51_nums; i++) {
+               if (spec->smart51_idxs[i] < 0)
+                       continue;
+               snd_hda_codec_amp_stereo(codec, spec->aa_mix_nid,
+                                        HDA_INPUT, spec->smart51_idxs[i],
                                         HDA_AMP_MUTE, val);
        }
 }
-static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
+
+static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin)
 {
-       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct via_spec *spec = codec->spec;
        int i;
 
-       for (i = 0; i < cfg->num_inputs; i++) {
-               if (pin == cfg->inputs[i].pin)
-                       return cfg->inputs[i].type <= AUTO_PIN_LINE_IN;
-       }
-       return 0;
-}
-
-static int via_smart51_info(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-       return 0;
+       for (i = 0; i < spec->smart51_nums; i++)
+               if (spec->smart51_pins[i] == pin)
+                       return true;
+       return false;
 }
 
 static int via_smart51_get(struct snd_kcontrol *kcontrol,
@@ -943,23 +955,8 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       const struct auto_pin_cfg *cfg = &spec->autocfg;
-       int on = 1;
-       int i;
 
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               int ctl = snd_hda_codec_read(codec, nid, 0,
-                                            AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
-                       continue;
-               if (cfg->inputs[i].type == AUTO_PIN_MIC &&
-                   spec->hp_independent_mode && spec->codec_type != VT1718S)
-                       continue; /* ignore FMic for independent HP */
-               if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN))
-                       on = 0;
-       }
-       *ucontrol->value.integer.value = on;
+       *ucontrol->value.integer.value = spec->smart51_enabled;
        return 0;
 }
 
@@ -968,21 +965,14 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       const struct auto_pin_cfg *cfg = &spec->autocfg;
        int out_in = *ucontrol->value.integer.value
                ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
        int i;
 
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
+       for (i = 0; i < spec->smart51_nums; i++) {
+               hda_nid_t nid = spec->smart51_pins[i];
                unsigned int parm;
 
-               if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
-                       continue;
-               if (cfg->inputs[i].type == AUTO_PIN_MIC &&
-                   spec->hp_independent_mode && spec->codec_type != VT1718S)
-                       continue; /* don't retask FMic for independent HP */
-
                parm = snd_hda_codec_read(codec, nid, 0,
                                          AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
                parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
@@ -994,171 +984,59 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
                        mute_aa_path(codec, 1);
                        notify_aa_path_ctls(codec);
                }
-               if (spec->codec_type == VT1718S) {
-                       snd_hda_codec_amp_stereo(
-                                       codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                                       HDA_AMP_UNMUTE);
-               }
-               if (cfg->inputs[i].type == AUTO_PIN_MIC) {
-                       if (spec->codec_type == VT1708S
-                           || spec->codec_type == VT1716S) {
-                               /* input = index 1 (AOW3) */
-                               snd_hda_codec_write(
-                                       codec, nid, 0,
-                                       AC_VERB_SET_CONNECT_SEL, 1);
-                               snd_hda_codec_amp_stereo(
-                                       codec, nid, HDA_OUTPUT,
-                                       0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
-                       }
-               }
        }
        spec->smart51_enabled = *ucontrol->value.integer.value;
        set_widgets_power_state(codec);
        return 1;
 }
 
-static const struct snd_kcontrol_new via_smart51_mixer[2] = {
-       {
-        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name = "Smart 5.1",
-        .count = 1,
-        .info = via_smart51_info,
-        .get = via_smart51_get,
-        .put = via_smart51_put,
-        },
-       {
-        .iface = NID_MAPPING,
-        .name = "Smart 5.1",
-       }
+static const struct snd_kcontrol_new via_smart51_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Smart 5.1",
+       .count = 1,
+       .info = snd_ctl_boolean_mono_info,
+       .get = via_smart51_get,
+       .put = via_smart51_put,
 };
 
-static int via_smart51_build(struct via_spec *spec)
+static int via_smart51_build(struct hda_codec *codec)
 {
-       struct snd_kcontrol_new *knew;
-       const struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t nid;
-       int i;
+       struct via_spec *spec = codec->spec;
 
-       if (!cfg)
-               return 0;
-       if (cfg->line_outs > 2)
+       if (!spec->smart51_nums)
                return 0;
-
-       knew = via_clone_control(spec, &via_smart51_mixer[0]);
-       if (knew == NULL)
+       if (!via_clone_control(spec, &via_smart51_mixer))
                return -ENOMEM;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               nid = cfg->inputs[i].pin;
-               if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) {
-                       knew = via_clone_control(spec, &via_smart51_mixer[1]);
-                       if (knew == NULL)
-                               return -ENOMEM;
-                       knew->subdevice = nid;
-                       break;
-               }
-       }
-
        return 0;
 }
 
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1708_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = via_mux_enum_info,
-               .get = via_mux_enum_get,
-               .put = via_mux_enum_put,
-       },
-       { } /* end */
-};
-
-/* check AA path's mute statue */
-static int is_aa_path_mute(struct hda_codec *codec)
+/* check AA path's mute status */
+static bool is_aa_path_mute(struct hda_codec *codec)
 {
-       int mute = 1;
-       hda_nid_t  nid_mixer;
-       int start_idx;
-       int end_idx;
-       int i;
        struct via_spec *spec = codec->spec;
-       /* get nid of MW0 and start & end index */
-       switch (spec->codec_type) {
-       case VT1708B_8CH:
-       case VT1708B_4CH:
-       case VT1708S:
-       case VT1716S:
-               nid_mixer = 0x16;
-               start_idx = 2;
-               end_idx = 4;
-               break;
-       case VT1702:
-               nid_mixer = 0x1a;
-               start_idx = 1;
-               end_idx = 3;
-               break;
-       case VT1718S:
-               nid_mixer = 0x21;
-               start_idx = 1;
-               end_idx = 3;
-               break;
-       case VT2002P:
-       case VT1812:
-       case VT1802:
-               nid_mixer = 0x21;
-               start_idx = 0;
-               end_idx = 2;
-               break;
-       default:
-               return 0;
-       }
-       /* check AA path's mute status */
-       for (i = start_idx; i <= end_idx; i++) {
-               unsigned int con_list = snd_hda_codec_read(
-                       codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
-               int shift = 8 * (i % 4);
-               hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
-               unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
-               if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
-                       /* check mute status while the pin is connected */
-                       int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
-                                                           HDA_INPUT, i) >> 7;
-                       int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
-                                                           HDA_INPUT, i) >> 7;
-                       if (!mute_l || !mute_r) {
-                               mute = 0;
-                               break;
-                       }
+       const struct hda_amp_list *p;
+       int i, ch, v;
+
+       for (i = 0; i < spec->num_loopbacks; i++) {
+               p = &spec->loopback_list[i];
+               for (ch = 0; ch < 2; ch++) {
+                       v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir,
+                                                  p->idx);
+                       if (!(v & HDA_AMP_MUTE) && v > 0)
+                               return false;
                }
        }
-       return mute;
+       return true;
 }
 
 /* enter/exit analog low-current mode */
-static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
+static void analog_low_current_mode(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
-       static int saved_stream_idle = 1; /* saved stream idle status */
-       int enable = is_aa_path_mute(codec);
-       unsigned int verb = 0;
-       unsigned int parm = 0;
+       bool enable;
+       unsigned int verb, parm;
 
-       if (stream_idle == -1)  /* stream status did not change */
-               enable = enable && saved_stream_idle;
-       else {
-               enable = enable && stream_idle;
-               saved_stream_idle = stream_idle;
-       }
+       enable = is_aa_path_mute(codec) && (spec->opened_streams != 0);
 
        /* decide low current mode's verb & parameter */
        switch (spec->codec_type) {
@@ -1193,119 +1071,69 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
-static const struct hda_verb vt1708_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
-       /*
-        * Set up output mixers (0x19 - 0x1b)
-        */
-       /* set vol=0 to output mixers */
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* Setup default input MW0 to PW4 */
-       {0x20, AC_VERB_SET_CONNECT_SEL, 0},
-       /* PW9 Output enable */
-       {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+static const struct hda_verb vt1708_init_verbs[] = {
        /* power down jack detect function */
        {0x1, 0xf81, 0x1},
        { }
 };
 
-static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
+static void set_stream_open(struct hda_codec *codec, int bit, bool active)
+{
+       struct via_spec *spec = codec->spec;
+
+       if (active)
+               spec->opened_streams |= bit;
+       else
+               spec->opened_streams &= ~bit;
+       analog_low_current_mode(codec);
+}
+
+static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo,
                                 struct hda_codec *codec,
                                 struct snd_pcm_substream *substream)
 {
        struct via_spec *spec = codec->spec;
-       int idle = substream->pstr->substream_opened == 1
-               && substream->ref_count == 0;
-       analog_low_current_mode(codec, idle);
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
-                                            hinfo);
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       int err;
+
+       spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums;
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+       set_stream_open(codec, STREAM_MULTI_OUT, true);
+       err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                           hinfo);
+       if (err < 0) {
+               set_stream_open(codec, STREAM_MULTI_OUT, false);
+               return err;
+       }
+       return 0;
 }
 
-static void playback_multi_pcm_prep_0(struct hda_codec *codec,
-                                     unsigned int stream_tag,
-                                     unsigned int format,
-                                     struct snd_pcm_substream *substream)
+static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream)
+{
+       set_stream_open(codec, STREAM_MULTI_OUT, false);
+       return 0;
+}
+
+static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
 {
        struct via_spec *spec = codec->spec;
-       struct hda_multi_out *mout = &spec->multiout;
-       const hda_nid_t *nids = mout->dac_nids;
-       int chs = substream->runtime->channels;
-       int i;
 
-       mutex_lock(&codec->spdif_mutex);
-       if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
-               if (chs == 2 &&
-                   snd_hda_is_supported_format(codec, mout->dig_out_nid,
-                                               format) &&
-                   !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
-                       mout->dig_out_used = HDA_DIG_ANALOG_DUP;
-                       /* turn off SPDIF once; otherwise the IEC958 bits won't
-                        * be updated */
-                       if (codec->spdif_ctls & AC_DIG1_ENABLE)
-                               snd_hda_codec_write(codec, mout->dig_out_nid, 0,
-                                                   AC_VERB_SET_DIGI_CONVERT_1,
-                                                   codec->spdif_ctls &
-                                                       ~AC_DIG1_ENABLE & 0xff);
-                       snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
-                                                  stream_tag, 0, format);
-                       /* turn on again (if needed) */
-                       if (codec->spdif_ctls & AC_DIG1_ENABLE)
-                               snd_hda_codec_write(codec, mout->dig_out_nid, 0,
-                                                   AC_VERB_SET_DIGI_CONVERT_1,
-                                                   codec->spdif_ctls & 0xff);
-               } else {
-                       mout->dig_out_used = 0;
-                       snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
-                                                  0, 0, 0);
-               }
-       }
-       mutex_unlock(&codec->spdif_mutex);
-
-       /* front */
-       snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
-                                  0, format);
-
-       if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]
-           && !spec->hp_independent_mode)
-               /* headphone out will just decode front left/right (stereo) */
-               snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
-                                          0, format);
-
-       /* extra outputs copied from front */
-       for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
-               if (mout->extra_out_nid[i])
-                       snd_hda_codec_setup_stream(codec,
-                                                  mout->extra_out_nid[i],
-                                                  stream_tag, 0, format);
-
-       /* surrounds */
-       for (i = 1; i < mout->num_dacs; i++) {
-               if (chs >= (i + 1) * 2) /* independent out */
-                       snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
-                                                  i * 2, format);
-               else /* copy front */
-                       snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
-                                                  0, format);
-       }
+       if (snd_BUG_ON(!spec->hp_dac_nid))
+               return -EINVAL;
+       set_stream_open(codec, STREAM_INDEP_HP, true);
+       return 0;
+}
+
+static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo,
+                                    struct hda_codec *codec,
+                                    struct snd_pcm_substream *substream)
+{
+       set_stream_open(codec, STREAM_INDEP_HP, false);
+       return 0;
 }
 
 static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -1315,18 +1143,36 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
                                          struct snd_pcm_substream *substream)
 {
        struct via_spec *spec = codec->spec;
-       struct hda_multi_out *mout = &spec->multiout;
-       const hda_nid_t *nids = mout->dac_nids;
 
-       if (substream->number == 0)
-               playback_multi_pcm_prep_0(codec, stream_tag, format,
-                                         substream);
-       else {
-               if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
-                   spec->hp_independent_mode)
-                       snd_hda_codec_setup_stream(codec, mout->hp_nid,
-                                                  stream_tag, 0, format);
-       }
+       mutex_lock(&spec->config_mutex);
+       setup_playback_multi_pcm(spec);
+       snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+                                        format, substream);
+       /* remember for dynamic DAC switch with indep-HP */
+       spec->active_streams |= STREAM_MULTI_OUT;
+       spec->cur_dac_stream_tag = stream_tag;
+       spec->cur_dac_format = format;
+       mutex_unlock(&spec->config_mutex);
+       vt1708_start_hp_work(spec);
+       return 0;
+}
+
+static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      unsigned int stream_tag,
+                                      unsigned int format,
+                                      struct snd_pcm_substream *substream)
+{
+       struct via_spec *spec = codec->spec;
+
+       mutex_lock(&spec->config_mutex);
+       if (spec->hp_independent_mode)
+               snd_hda_codec_setup_stream(codec, spec->hp_dac_nid,
+                                          stream_tag, 0, format);
+       spec->active_streams |= STREAM_INDEP_HP;
+       spec->cur_hp_stream_tag = stream_tag;
+       spec->cur_hp_format = format;
+       mutex_unlock(&spec->config_mutex);
        vt1708_start_hp_work(spec);
        return 0;
 }
@@ -1336,37 +1182,26 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
                                    struct snd_pcm_substream *substream)
 {
        struct via_spec *spec = codec->spec;
-       struct hda_multi_out *mout = &spec->multiout;
-       const hda_nid_t *nids = mout->dac_nids;
-       int i;
 
-       if (substream->number == 0) {
-               for (i = 0; i < mout->num_dacs; i++)
-                       snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
-
-               if (mout->hp_nid && !spec->hp_independent_mode)
-                       snd_hda_codec_setup_stream(codec, mout->hp_nid,
-                                                  0, 0, 0);
-
-               for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
-                       if (mout->extra_out_nid[i])
-                               snd_hda_codec_setup_stream(codec,
-                                                       mout->extra_out_nid[i],
-                                                       0, 0, 0);
-               mutex_lock(&codec->spdif_mutex);
-               if (mout->dig_out_nid &&
-                   mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
-                       snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
-                                                  0, 0, 0);
-                       mout->dig_out_used = 0;
-               }
-               mutex_unlock(&codec->spdif_mutex);
-       } else {
-               if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
-                   spec->hp_independent_mode)
-                       snd_hda_codec_setup_stream(codec, mout->hp_nid,
-                                                  0, 0, 0);
-       }
+       mutex_lock(&spec->config_mutex);
+       snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+       spec->active_streams &= ~STREAM_MULTI_OUT;
+       mutex_unlock(&spec->config_mutex);
+       vt1708_stop_hp_work(spec);
+       return 0;
+}
+
+static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      struct snd_pcm_substream *substream)
+{
+       struct via_spec *spec = codec->spec;
+
+       mutex_lock(&spec->config_mutex);
+       if (spec->hp_independent_mode)
+               snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0);
+       spec->active_streams &= ~STREAM_INDEP_HP;
+       mutex_unlock(&spec->config_mutex);
        vt1708_stop_hp_work(spec);
        return 0;
 }
@@ -1435,47 +1270,127 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
        return 0;
 }
 
-static const struct hda_pcm_stream vt1708_pcm_analog_playback = {
-       .substreams = 2,
+/* analog capture with dynamic ADC switching */
+static int via_dyn_adc_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 via_spec *spec = codec->spec;
+       int adc_idx = spec->inputs[spec->cur_mux[0]].adc_idx;
+
+       mutex_lock(&spec->config_mutex);
+       spec->cur_adc = spec->adc_nids[adc_idx];
+       spec->cur_adc_stream_tag = stream_tag;
+       spec->cur_adc_format = format;
+       snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
+       mutex_unlock(&spec->config_mutex);
+       return 0;
+}
+
+static int via_dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                          struct hda_codec *codec,
+                                          struct snd_pcm_substream *substream)
+{
+       struct via_spec *spec = codec->spec;
+
+       mutex_lock(&spec->config_mutex);
+       snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+       spec->cur_adc = 0;
+       mutex_unlock(&spec->config_mutex);
+       return 0;
+}
+
+/* re-setup the stream if running; called from input-src put */
+static bool via_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
+{
+       struct via_spec *spec = codec->spec;
+       int adc_idx = spec->inputs[cur].adc_idx;
+       hda_nid_t adc = spec->adc_nids[adc_idx];
+       bool ret = false;
+
+       mutex_lock(&spec->config_mutex);
+       if (spec->cur_adc && spec->cur_adc != adc) {
+               /* stream is running, let's swap the current ADC */
+               __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+               spec->cur_adc = adc;
+               snd_hda_codec_setup_stream(codec, adc,
+                                          spec->cur_adc_stream_tag, 0,
+                                          spec->cur_adc_format);
+               ret = true;
+       }
+       mutex_unlock(&spec->config_mutex);
+       return ret;
+}
+
+static const struct hda_pcm_stream via_pcm_analog_playback = {
+       .substreams = 1,
        .channels_min = 2,
        .channels_max = 8,
-       .nid = 0x10, /* NID to query formats and rates */
+       /* NID is set in via_build_pcms */
        .ops = {
-               .open = via_playback_pcm_open,
+               .open = via_playback_multi_pcm_open,
+               .close = via_playback_multi_pcm_close,
                .prepare = via_playback_multi_pcm_prepare,
                .cleanup = via_playback_multi_pcm_cleanup
        },
 };
 
+static const struct hda_pcm_stream via_pcm_hp_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in via_build_pcms */
+       .ops = {
+               .open = via_playback_hp_pcm_open,
+               .close = via_playback_hp_pcm_close,
+               .prepare = via_playback_hp_pcm_prepare,
+               .cleanup = via_playback_hp_pcm_cleanup
+       },
+};
+
 static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
-       .substreams = 2,
+       .substreams = 1,
        .channels_min = 2,
        .channels_max = 8,
-       .nid = 0x10, /* NID to query formats and rates */
+       /* NID is set in via_build_pcms */
        /* We got noisy outputs on the right channel on VT1708 when
         * 24bit samples are used.  Until any workaround is found,
         * disable the 24bit format, so far.
         */
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
        .ops = {
-               .open = via_playback_pcm_open,
+               .open = via_playback_multi_pcm_open,
+               .close = via_playback_multi_pcm_close,
                .prepare = via_playback_multi_pcm_prepare,
                .cleanup = via_playback_multi_pcm_cleanup
        },
 };
 
-static const struct hda_pcm_stream vt1708_pcm_analog_capture = {
-       .substreams = 2,
+static const struct hda_pcm_stream via_pcm_analog_capture = {
+       .substreams = 1, /* will be changed in via_build_pcms() */
        .channels_min = 2,
        .channels_max = 2,
-       .nid = 0x15, /* NID to query formats and rates */
+       /* NID is set in via_build_pcms */
        .ops = {
                .prepare = via_capture_pcm_prepare,
                .cleanup = via_capture_pcm_cleanup
        },
 };
 
-static const struct hda_pcm_stream vt1708_pcm_digital_playback = {
+static const struct hda_pcm_stream via_pcm_dyn_adc_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in via_build_pcms */
+       .ops = {
+               .prepare = via_dyn_adc_capture_pcm_prepare,
+               .cleanup = via_dyn_adc_capture_pcm_cleanup,
+       },
+};
+
+static const struct hda_pcm_stream via_pcm_digital_playback = {
        .substreams = 1,
        .channels_min = 2,
        .channels_max = 2,
@@ -1488,19 +1403,47 @@ static const struct hda_pcm_stream vt1708_pcm_digital_playback = {
        },
 };
 
-static const struct hda_pcm_stream vt1708_pcm_digital_capture = {
+static const struct hda_pcm_stream via_pcm_digital_capture = {
        .substreams = 1,
        .channels_min = 2,
        .channels_max = 2,
 };
 
+/*
+ * slave controls for virtual master
+ */
+static const char * const via_slave_vols[] = {
+       "Front Playback Volume",
+       "Surround Playback Volume",
+       "Center Playback Volume",
+       "LFE Playback Volume",
+       "Side Playback Volume",
+       "Headphone Playback Volume",
+       "Speaker Playback Volume",
+       NULL,
+};
+
+static const char * const via_slave_sws[] = {
+       "Front Playback Switch",
+       "Surround Playback Switch",
+       "Center Playback Switch",
+       "LFE Playback Switch",
+       "Side Playback Switch",
+       "Headphone Playback Switch",
+       "Speaker Playback Switch",
+       NULL,
+};
+
 static int via_build_controls(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        struct snd_kcontrol *kctl;
-       const struct snd_kcontrol_new *knew;
        int err, i;
 
+       if (spec->set_widgets_power_state)
+               if (!via_clone_control(spec, &via_pin_power_ctl_enum))
+                       return -ENOMEM;
+
        for (i = 0; i < spec->num_mixers; i++) {
                err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
                if (err < 0)
@@ -1509,6 +1452,7 @@ static int via_build_controls(struct hda_codec *codec)
 
        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;
@@ -1524,6 +1468,23 @@ static int via_build_controls(struct hda_codec *codec)
                        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->multiout.dac_nids[0],
+                                       HDA_OUTPUT, vmaster_tlv);
+               err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+                                         vmaster_tlv, via_slave_vols);
+               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, via_slave_sws);
+               if (err < 0)
+                       return err;
+       }
+
        /* assign Capture Source enums to NID */
        kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
        for (i = 0; kctl && i < kctl->count; i++) {
@@ -1532,22 +1493,9 @@ static int via_build_controls(struct hda_codec *codec)
                        return err;
        }
 
-       /* other nid->control mapping */
-       for (i = 0; i < spec->num_mixers; i++) {
-               for (knew = spec->mixers[i]; knew->name; knew++) {
-                       if (knew->iface != NID_MAPPING)
-                               continue;
-                       kctl = snd_hda_find_mixer_ctl(codec, knew->name);
-                       if (kctl == NULL)
-                               continue;
-                       err = snd_hda_add_nid(codec, kctl, 0,
-                                             knew->subdevice);
-               }
-       }
-
        /* init power states */
        set_widgets_power_state(codec);
-       analog_low_current_mode(codec, 1);
+       analog_low_current_mode(codec);
 
        via_free_kctls(codec); /* no longer needed */
        return 0;
@@ -1561,36 +1509,71 @@ static int via_build_pcms(struct hda_codec *codec)
        codec->num_pcms = 1;
        codec->pcm_info = info;
 
+       snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
+                "%s Analog", codec->chip_name);
        info->name = spec->stream_name_analog;
+
+       if (!spec->stream_analog_playback)
+               spec->stream_analog_playback = &via_pcm_analog_playback;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-               *(spec->stream_analog_playback);
+               *spec->stream_analog_playback;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
                spec->multiout.dac_nids[0];
-       info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
-
        info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
                spec->multiout.max_channels;
 
+       if (!spec->stream_analog_capture) {
+               if (spec->dyn_adc_switch)
+                       spec->stream_analog_capture =
+                               &via_pcm_dyn_adc_analog_capture;
+               else
+                       spec->stream_analog_capture = &via_pcm_analog_capture;
+       }
+       info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+               *spec->stream_analog_capture;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+       if (!spec->dyn_adc_switch)
+               info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
+                       spec->num_adc_nids;
+
        if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
                codec->num_pcms++;
                info++;
+               snprintf(spec->stream_name_digital,
+                        sizeof(spec->stream_name_digital),
+                        "%s Digital", codec->chip_name);
                info->name = spec->stream_name_digital;
                info->pcm_type = HDA_PCM_TYPE_SPDIF;
                if (spec->multiout.dig_out_nid) {
+                       if (!spec->stream_digital_playback)
+                               spec->stream_digital_playback =
+                                       &via_pcm_digital_playback;
                        info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-                               *(spec->stream_digital_playback);
+                               *spec->stream_digital_playback;
                        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
                                spec->multiout.dig_out_nid;
                }
                if (spec->dig_in_nid) {
+                       if (!spec->stream_digital_capture)
+                               spec->stream_digital_capture =
+                                       &via_pcm_digital_capture;
                        info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-                               *(spec->stream_digital_capture);
+                               *spec->stream_digital_capture;
                        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
                                spec->dig_in_nid;
                }
        }
 
+       if (spec->hp_dac_nid) {
+               codec->num_pcms++;
+               info++;
+               snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp),
+                        "%s HP", codec->chip_name);
+               info->name = spec->stream_name_hp;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+                       spec->hp_dac_nid;
+       }
        return 0;
 }
 
@@ -1603,57 +1586,62 @@ static void via_free(struct hda_codec *codec)
 
        via_free_kctls(codec);
        vt1708_stop_hp_work(spec);
-       kfree(codec->spec);
+       kfree(spec->bind_cap_vol);
+       kfree(spec->bind_cap_sw);
+       kfree(spec);
 }
 
-/* mute internal speaker if HP is plugged */
-static void via_hp_automute(struct hda_codec *codec)
+/* mute/unmute outputs */
+static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
+                               hda_nid_t *pins, bool mute)
 {
-       unsigned int present = 0;
-       struct via_spec *spec = codec->spec;
-
-       present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
-
-       if (!spec->hp_independent_mode) {
-               struct snd_ctl_elem_id id;
-               /* auto mute */
-               snd_hda_codec_amp_stereo(
-                       codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0,
-                       HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-               /* notify change */
-               memset(&id, 0, sizeof(id));
-               id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-               strcpy(id.name, "Front Playback Switch");
-               snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                              &id);
+       int i;
+       for (i = 0; i < num_pins; i++) {
+               unsigned int parm = snd_hda_codec_read(codec, pins[i], 0,
+                                         AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               if (parm & AC_PINCTL_IN_EN)
+                       continue;
+               if (mute)
+                       parm &= ~AC_PINCTL_OUT_EN;
+               else
+                       parm |= AC_PINCTL_OUT_EN;
+               snd_hda_codec_write(codec, pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, parm);
        }
 }
 
-/* mute mono out if HP or Line out is plugged */
-static void via_mono_automute(struct hda_codec *codec)
+/* mute internal speaker if line-out is plugged */
+static void via_line_automute(struct hda_codec *codec, int present)
 {
-       unsigned int hp_present, lineout_present;
        struct via_spec *spec = codec->spec;
 
-       if (spec->codec_type != VT1716S)
+       if (!spec->autocfg.speaker_outs)
                return;
-
-       lineout_present = snd_hda_jack_detect(codec,
+       if (!present)
+               present = snd_hda_jack_detect(codec,
                                              spec->autocfg.line_out_pins[0]);
+       toggle_output_mutes(codec, spec->autocfg.speaker_outs,
+                           spec->autocfg.speaker_pins,
+                           present);
+}
 
-       /* Mute Mono Out if Line Out is plugged */
-       if (lineout_present) {
-               snd_hda_codec_amp_stereo(
-                       codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE);
-               return;
-       }
+/* mute internal speaker if HP is plugged */
+static void via_hp_automute(struct hda_codec *codec)
+{
+       int present = 0;
+       int nums;
+       struct via_spec *spec = codec->spec;
 
-       hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
+       if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0])
+               present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
 
-       if (!spec->hp_independent_mode)
-               snd_hda_codec_amp_stereo(
-                       codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                       hp_present ? HDA_AMP_MUTE : 0);
+       if (spec->smart51_enabled)
+               nums = spec->autocfg.line_outs + spec->smart51_nums;
+       else
+               nums = spec->autocfg.line_outs;
+       toggle_output_mutes(codec, nums, spec->autocfg.line_out_pins, present);
+
+       via_line_automute(codec, present);
 }
 
 static void via_gpio_control(struct hda_codec *codec)
@@ -1678,9 +1666,9 @@ static void via_gpio_control(struct hda_codec *codec)
 
        if (gpio_data == 0x02) {
                /* unmute line out */
-               snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
-                                        HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
-
+               snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   PIN_OUT);
                if (vol_counter & 0x20) {
                        /* decrease volume */
                        if (vol > master_vol)
@@ -1697,73 +1685,12 @@ static void via_gpio_control(struct hda_codec *codec)
                }
        } else if (!(gpio_data & 0x02)) {
                /* mute line out */
-               snd_hda_codec_amp_stereo(codec,
-                                        spec->autocfg.line_out_pins[0],
-                                        HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                                        HDA_AMP_MUTE);
-       }
-}
-
-/* mute Internal-Speaker if HP is plugged */
-static void via_speaker_automute(struct hda_codec *codec)
-{
-       unsigned int hp_present;
-       struct via_spec *spec = codec->spec;
-
-       if (!VT2002P_COMPATIBLE(spec))
-               return;
-
-       hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
-
-       if (!spec->hp_independent_mode) {
-               struct snd_ctl_elem_id id;
-               snd_hda_codec_amp_stereo(
-                       codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0,
-                       HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
-               /* notify change */
-               memset(&id, 0, sizeof(id));
-               id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-               strcpy(id.name, "Speaker Playback Switch");
-               snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                              &id);
-       }
-}
-
-/* mute line-out and internal speaker if HP is plugged */
-static void via_hp_bind_automute(struct hda_codec *codec)
-{
-       /* use long instead of int below just to avoid an internal compiler
-        * error with gcc 4.0.x
-        */
-       unsigned long hp_present, present = 0;
-       struct via_spec *spec = codec->spec;
-       int i;
-
-       if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0])
-               return;
-
-       hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
-
-       present = snd_hda_jack_detect(codec, spec->autocfg.line_out_pins[0]);
-
-       if (!spec->hp_independent_mode) {
-               /* Mute Line-Outs */
-               for (i = 0; i < spec->autocfg.line_outs; i++)
-                       snd_hda_codec_amp_stereo(
-                               codec, spec->autocfg.line_out_pins[i],
-                               HDA_OUTPUT, 0,
-                               HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
-               if (hp_present)
-                       present = hp_present;
+               snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   0);
        }
-       /* Speakers */
-       for (i = 0; i < spec->autocfg.speaker_outs; i++)
-               snd_hda_codec_amp_stereo(
-                       codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0,
-                       HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
 
-
 /* unsolicited event for jack sensing */
 static void via_unsol_event(struct hda_codec *codec,
                                  unsigned int res)
@@ -1775,43 +1702,10 @@ static void via_unsol_event(struct hda_codec *codec,
 
        res &= ~VIA_JACK_EVENT;
 
-       if (res == VIA_HP_EVENT)
+       if (res == VIA_HP_EVENT || res == VIA_LINE_EVENT)
                via_hp_automute(codec);
        else if (res == VIA_GPIO_EVENT)
                via_gpio_control(codec);
-       else if (res == VIA_MONO_EVENT)
-               via_mono_automute(codec);
-       else if (res == VIA_SPEAKER_EVENT)
-               via_speaker_automute(codec);
-       else if (res == VIA_BIND_HP_EVENT)
-               via_hp_bind_automute(codec);
-}
-
-static int via_init(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int i;
-       for (i = 0; i < spec->num_iverbs; i++)
-               snd_hda_sequence_write(codec, spec->init_verbs[i]);
-
-       /* Lydia Add for EAPD enable */
-       if (!spec->dig_in_nid) { /* No Digital In connection */
-               if (spec->dig_in_pin) {
-                       snd_hda_codec_write(codec, spec->dig_in_pin, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           PIN_OUT);
-                       snd_hda_codec_write(codec, spec->dig_in_pin, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
-               }
-       } else /* enable SPDIF-input pin */
-               snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
-
-       /* assign slave outs */
-       if (spec->slave_dig_outs[0])
-               codec->slave_dig_outs = spec->slave_dig_outs;
-
-       return 0;
 }
 
 #ifdef SND_HDA_NEEDS_RESUME
@@ -1833,11 +1727,15 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 
 /*
  */
+
+static int via_init(struct hda_codec *codec);
+
 static const struct hda_codec_ops via_patch_ops = {
        .build_controls = via_build_controls,
        .build_pcms = via_build_pcms,
        .init = via_init,
        .free = via_free,
+       .unsol_event = via_unsol_event,
 #ifdef SND_HDA_NEEDS_RESUME
        .suspend = via_suspend,
 #endif
@@ -1846,2757 +1744,1439 @@ static const struct hda_codec_ops via_patch_ops = {
 #endif
 };
 
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
-                                    const struct auto_pin_cfg *cfg)
+static bool is_empty_dac(struct hda_codec *codec, hda_nid_t dac)
 {
+       struct via_spec *spec = codec->spec;
        int i;
-       hda_nid_t nid;
 
-       spec->multiout.num_dacs = cfg->line_outs;
+       for (i = 0; i < spec->multiout.num_dacs; i++) {
+               if (spec->multiout.dac_nids[i] == dac)
+                       return false;
+       }
+       if (spec->hp_dac_nid == dac)
+               return false;
+       return true;
+}
 
-       spec->multiout.dac_nids = spec->private_dac_nids;
+static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid,
+                               hda_nid_t target_dac, int with_aa_mix,
+                               struct nid_path *path, int depth)
+{
+       struct via_spec *spec = codec->spec;
+       hda_nid_t conn[8];
+       int i, nums;
+
+       if (nid == spec->aa_mix_nid) {
+               if (!with_aa_mix)
+                       return false;
+               with_aa_mix = 2; /* mark aa-mix is included */
+       }
+
+       nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn));
+       for (i = 0; i < nums; i++) {
+               if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT)
+                       continue;
+               if (conn[i] == target_dac || is_empty_dac(codec, conn[i])) {
+                       /* aa-mix is requested but not included? */
+                       if (!(spec->aa_mix_nid && with_aa_mix == 1))
+                               goto found;
+               }
+       }
+       if (depth >= MAX_NID_PATH_DEPTH)
+               return false;
+       for (i = 0; i < nums; i++) {
+               unsigned int type;
+               type = get_wcaps_type(get_wcaps(codec, conn[i]));
+               if (type == AC_WID_AUD_OUT)
+                       continue;
+               if (__parse_output_path(codec, conn[i], target_dac,
+                                       with_aa_mix, path, depth + 1))
+                       goto found;
+       }
+       return false;
+
+ found:
+       path->path[path->depth] = conn[i];
+       path->idx[path->depth] = i;
+       if (nums > 1 && get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX)
+               path->multi[path->depth] = 1;
+       path->depth++;
+       return true;
+}
 
-       for (i = 0; i < 4; i++) {
+static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid,
+                             hda_nid_t target_dac, int with_aa_mix,
+                             struct nid_path *path)
+{
+       if (__parse_output_path(codec, nid, target_dac, with_aa_mix, path, 1)) {
+               path->path[path->depth] = nid;
+               path->depth++;
+               snd_printdd("output-path: depth=%d, %02x/%02x/%02x/%02x/%02x\n",
+                           path->depth, path->path[0], path->path[1],
+                           path->path[2], path->path[3], path->path[4]);
+               return true;
+       }
+       return false;
+}
+
+static int via_auto_fill_dac_nids(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, dac_num;
+       hda_nid_t nid;
+
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       dac_num = 0;
+       for (i = 0; i < cfg->line_outs; i++) {
+               hda_nid_t dac = 0;
                nid = cfg->line_out_pins[i];
-               if (nid) {
-                       /* config dac list */
-                       switch (i) {
-                       case AUTO_SEQ_FRONT:
-                               spec->private_dac_nids[i] = 0x10;
-                               break;
-                       case AUTO_SEQ_CENLFE:
-                               spec->private_dac_nids[i] = 0x12;
-                               break;
-                       case AUTO_SEQ_SURROUND:
-                               spec->private_dac_nids[i] = 0x11;
-                               break;
-                       case AUTO_SEQ_SIDE:
-                               spec->private_dac_nids[i] = 0x13;
-                               break;
-                       }
+               if (!nid)
+                       continue;
+               if (parse_output_path(codec, nid, 0, 0, &spec->out_path[i]))
+                       dac = spec->out_path[i].path[0];
+               if (!i && parse_output_path(codec, nid, dac, 1,
+                                           &spec->out_mix_path))
+                       dac = spec->out_mix_path.path[0];
+               if (dac) {
+                       spec->private_dac_nids[i] = dac;
+                       dac_num++;
                }
        }
+       if (!spec->out_path[0].depth && spec->out_mix_path.depth) {
+               spec->out_path[0] = spec->out_mix_path;
+               spec->out_mix_path.depth = 0;
+       }
+       spec->multiout.num_dacs = dac_num;
+       return 0;
+}
+
+static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
+                         int chs, bool check_dac, struct nid_path *path)
+{
+       struct via_spec *spec = codec->spec;
+       char name[32];
+       hda_nid_t dac, pin, sel, nid;
+       int err;
+
+       dac = check_dac ? path->path[0] : 0;
+       pin = path->path[path->depth - 1];
+       sel = path->depth > 1 ? path->path[1] : 0;
+
+       if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
+               nid = dac;
+       else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
+               nid = pin;
+       else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
+               nid = sel;
+       else
+               nid = 0;
+       if (nid) {
+               sprintf(name, "%s Playback Volume", pfx);
+               err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+                             HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+               if (err < 0)
+                       return err;
+               path->vol_ctl = nid;
+       }
 
+       if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE))
+               nid = dac;
+       else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE))
+               nid = pin;
+       else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_MUTE))
+               nid = sel;
+       else
+               nid = 0;
+       if (nid) {
+               sprintf(name, "%s Playback Switch", pfx);
+               err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+                             HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+               if (err < 0)
+                       return err;
+               path->mute_ctl = nid;
+       }
        return 0;
 }
 
+static void mangle_smart51(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct auto_pin_cfg_item *ins = cfg->inputs;
+       int i, j, nums, attr;
+       int pins[AUTO_CFG_MAX_INS];
+
+       for (attr = INPUT_PIN_ATTR_REAR; attr >= INPUT_PIN_ATTR_NORMAL; attr--) {
+               nums = 0;
+               for (i = 0; i < cfg->num_inputs; i++) {
+                       unsigned int def;
+                       if (ins[i].type > AUTO_PIN_LINE_IN)
+                               continue;
+                       def = snd_hda_codec_get_pincfg(codec, ins[i].pin);
+                       if (snd_hda_get_input_pin_attr(def) != attr)
+                               continue;
+                       for (j = 0; j < nums; j++)
+                               if (ins[pins[j]].type < ins[i].type) {
+                                       memmove(pins + j + 1, pins + j,
+                                               (nums - j) * sizeof(int));
+                                       break;
+                               }
+                       pins[j] = i;
+                       nums++;
+               }
+               if (cfg->line_outs + nums < 3)
+                       continue;
+               for (i = 0; i < nums; i++) {
+                       hda_nid_t pin = ins[pins[i]].pin;
+                       spec->smart51_pins[spec->smart51_nums++] = pin;
+                       cfg->line_out_pins[cfg->line_outs++] = pin;
+                       if (cfg->line_outs == 3)
+                               break;
+               }
+               return;
+       }
+}
+
+static void copy_path_mixer_ctls(struct nid_path *dst, struct nid_path *src)
+{
+       dst->vol_ctl = src->vol_ctl;
+       dst->mute_ctl = src->mute_ctl;
+}
+
 /* add playback controls from the parsed DAC table */
-static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
+static int via_auto_create_multi_out_ctls(struct hda_codec *codec)
 {
-       char name[32];
+       struct via_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct nid_path *path;
        static const char * const chname[4] = {
                "Front", "Surround", "C/LFE", "Side"
        };
-       hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
-       int i, err;
-
-       for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
-               nid = cfg->line_out_pins[i];
+       int i, idx, err;
+       int old_line_outs;
 
-               if (!nid)
-                       continue;
+       /* check smart51 */
+       old_line_outs = cfg->line_outs;
+       if (cfg->line_outs == 1)
+               mangle_smart51(codec);
 
-               nid_vol = nid_vols[i];
-
-               if (i == AUTO_SEQ_CENLFE) {
-                       /* Center/LFE */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                       "Center Playback Volume",
-                                       HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
-                                                           HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "LFE Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "Center Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "LFE Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else if (i == AUTO_SEQ_FRONT) {
-                       /* add control to mixer index 0 */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Master Front Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "Master Front Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
+       err = via_auto_fill_dac_nids(codec);
+       if (err < 0)
+               return err;
 
-                       /* add control to PW3 */
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                                 HDA_OUTPUT));
+       if (spec->multiout.num_dacs < 3) {
+               spec->smart51_nums = 0;
+               cfg->line_outs = old_line_outs;
+       }
+       for (i = 0; i < cfg->line_outs; i++) {
+               hda_nid_t pin, dac;
+               pin = cfg->line_out_pins[i];
+               dac = spec->multiout.dac_nids[i];
+               if (!pin || !dac)
+                       continue;
+               path = spec->out_path + i;
+               if (i == HDA_CLFE) {
+                       err = create_ch_ctls(codec, "Center", 1, true, path);
                        if (err < 0)
                                return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                                 HDA_OUTPUT));
+                       err = create_ch_ctls(codec, "LFE", 2, true, path);
                        if (err < 0)
                                return err;
                } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
+                       const char *pfx = chname[i];
+                       if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
+                           cfg->line_outs == 1)
+                               pfx = "Speaker";
+                       err = create_ch_ctls(codec, pfx, 3, true, path);
                        if (err < 0)
                                return err;
                }
+               if (path != spec->out_path + i)
+                       copy_path_mixer_ctls(&spec->out_path[i], path);
+               if (path == spec->out_path && spec->out_mix_path.depth)
+                       copy_path_mixer_ctls(&spec->out_mix_path, path);
+       }
+
+       idx = get_connection_index(codec, spec->aa_mix_nid,
+                                  spec->multiout.dac_nids[0]);
+       if (idx >= 0) {
+               /* add control to mixer */
+               const char *name;
+               name = spec->out_mix_path.depth ?
+                       "PCM Loopback Playback Volume" : "PCM Playback Volume";
+               err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+                                     HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3,
+                                                         idx, HDA_INPUT));
+               if (err < 0)
+                       return err;
+               name = spec->out_mix_path.depth ?
+                       "PCM Loopback Playback Switch" : "PCM Playback Switch";
+               err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+                                     HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3,
+                                                         idx, HDA_INPUT));
+               if (err < 0)
+                       return err;
        }
 
+       cfg->line_outs = old_line_outs;
+
        return 0;
 }
 
-static void create_hp_imux(struct via_spec *spec)
+static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
 {
-       int i;
-       struct hda_input_mux *imux = &spec->private_imux[1];
-       static const char * const texts[] = { "OFF", "ON", NULL};
+       struct via_spec *spec = codec->spec;
+       struct nid_path *path;
+       bool check_dac;
+       int i, err;
+
+       if (!pin)
+               return 0;
+
+       if (!parse_output_path(codec, pin, 0, 0, &spec->hp_indep_path)) {
+               for (i = HDA_SIDE; i >= HDA_CLFE; i--) {
+                       if (i < spec->multiout.num_dacs &&
+                           parse_output_path(codec, pin,
+                                             spec->multiout.dac_nids[i], 0,
+                                             &spec->hp_indep_path)) {
+                               spec->hp_indep_shared = i;
+                               break;
+                       }
+               }
+       }
+       if (spec->hp_indep_path.depth) {
+               spec->hp_dac_nid = spec->hp_indep_path.path[0];
+               if (!spec->hp_indep_shared)
+                       spec->hp_path = spec->hp_indep_path;
+       }
+       /* optionally check front-path w/o AA-mix */
+       if (!spec->hp_path.depth)
+               parse_output_path(codec, pin,
+                                 spec->multiout.dac_nids[HDA_FRONT], 0,
+                                 &spec->hp_path);
 
-       /* for hp mode select */
-       for (i = 0; texts[i]; i++)
-               snd_hda_add_imux_item(imux, texts[i], i, NULL);
+       if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
+                              1, &spec->hp_mix_path) && !spec->hp_path.depth)
+               return 0;
 
-       spec->hp_mux = &spec->private_imux[1];
+       if (spec->hp_path.depth) {
+               path = &spec->hp_path;
+               check_dac = true;
+       } else {
+               path = &spec->hp_mix_path;
+               check_dac = false;
+       }
+       err = create_ch_ctls(codec, "Headphone", 3, check_dac, path);
+       if (err < 0)
+               return err;
+       if (check_dac)
+               copy_path_mixer_ctls(&spec->hp_mix_path, path);
+       else
+               copy_path_mixer_ctls(&spec->hp_path, path);
+       if (spec->hp_indep_path.depth)
+               copy_path_mixer_ctls(&spec->hp_indep_path, path);
+       return 0;
 }
 
-static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+static int via_auto_create_speaker_ctls(struct hda_codec *codec)
 {
+       struct via_spec *spec = codec->spec;
+       struct nid_path *path;
+       bool check_dac;
+       hda_nid_t pin, dac;
        int err;
 
-       if (!pin)
+       pin = spec->autocfg.speaker_pins[0];
+       if (!spec->autocfg.speaker_outs || !pin)
+               return 0;
+
+       if (parse_output_path(codec, pin, 0, 0, &spec->speaker_path))
+               dac = spec->speaker_path.path[0];
+       if (!dac)
+               parse_output_path(codec, pin,
+                                 spec->multiout.dac_nids[HDA_FRONT], 0,
+                                 &spec->speaker_path);
+       if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
+                              1, &spec->speaker_mix_path) && !dac)
                return 0;
 
-       spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
-       spec->hp_independent_mode_index = 1;
+       /* no AA-path for front? */
+       if (!spec->out_mix_path.depth && spec->speaker_mix_path.depth)
+               dac = 0;
 
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       spec->speaker_dac_nid = dac;
+       spec->multiout.extra_out_nid[0] = dac;
+       if (dac) {
+               path = &spec->speaker_path;
+               check_dac = true;
+       } else {
+               path = &spec->speaker_mix_path;
+               check_dac = false;
+       }
+       err = create_ch_ctls(codec, "Speaker", 3, check_dac, path);
        if (err < 0)
                return err;
-
-       create_hp_imux(spec);
-
+       if (check_dac)
+               copy_path_mixer_ctls(&spec->speaker_mix_path, path);
+       else
+               copy_path_mixer_ctls(&spec->speaker_path, path);
        return 0;
 }
 
-/* create playback/capture controls for input pins */
-static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                           const struct auto_pin_cfg *cfg,
-                                           hda_nid_t cap_nid,
-                                           const hda_nid_t pin_idxs[],
-                                           int num_idxs)
+#define via_aamix_ctl_info     via_pin_power_ctl_info
+
+static int via_aamix_ctl_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
 {
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx, type, type_idx = 0;
-
-       /* for internal loopback recording select */
-       for (idx = 0; idx < num_idxs; idx++) {
-               if (pin_idxs[idx] == 0xff) {
-                       snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL);
-                       break;
-               }
-       }
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               const char *label;
-               type = cfg->inputs[i].type;
-               for (idx = 0; idx < num_idxs; idx++)
-                       if (pin_idxs[idx] == cfg->inputs[i].pin)
-                               break;
-               if (idx >= num_idxs)
-                       continue;
-               if (i > 0 && type == cfg->inputs[i - 1].type)
-                       type_idx++;
-               else
-                       type_idx = 0;
-               label = hda_get_autocfg_input_label(codec, cfg, i);
-               if (spec->codec_type == VT1708S ||
-                   spec->codec_type == VT1702 ||
-                   spec->codec_type == VT1716S)
-                       err = via_new_analog_input(spec, label, type_idx,
-                                                  idx+1, cap_nid);
-               else
-                       err = via_new_analog_input(spec, label, type_idx,
-                                                  idx, cap_nid);
-               if (err < 0)
-                       return err;
-               snd_hda_add_imux_item(imux, label, idx, NULL);
-       }
+       ucontrol->value.enumerated.item[0] = spec->aamix_mode;
        return 0;
 }
 
-/* create playback/capture controls for input pins */
-static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
+static void update_aamix_paths(struct hda_codec *codec, int do_mix,
+                              struct nid_path *nomix, struct nid_path *mix)
 {
-       static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
-       return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
-                                               ARRAY_SIZE(pin_idxs));
+       if (do_mix) {
+               activate_output_path(codec, nomix, false, false);
+               activate_output_path(codec, mix, true, false);
+       } else {
+               activate_output_path(codec, mix, false, false);
+               activate_output_path(codec, nomix, true, false);
+       }
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1708_loopbacks[] = {
-       { 0x17, HDA_INPUT, 1 },
-       { 0x17, HDA_INPUT, 2 },
-       { 0x17, HDA_INPUT, 3 },
-       { 0x17, HDA_INPUT, 4 },
-       { } /* end */
-};
-#endif
-
-static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
+static int via_aamix_ctl_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
 {
-       unsigned int def_conf;
-       unsigned char seqassoc;
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       unsigned int val = ucontrol->value.enumerated.item[0];
 
-       def_conf = snd_hda_codec_get_pincfg(codec, nid);
-       seqassoc = (unsigned char) get_defcfg_association(def_conf);
-       seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
-       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
-           && (seqassoc == 0xf0 || seqassoc == 0xff)) {
-               def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
-               snd_hda_codec_set_pincfg(codec, nid, def_conf);
+       if (val == spec->aamix_mode)
+               return 0;
+       spec->aamix_mode = val;
+       /* update front path */
+       update_aamix_paths(codec, val, &spec->out_path[0], &spec->out_mix_path);
+       /* update HP path */
+       if (!spec->hp_independent_mode) {
+               update_aamix_paths(codec, val, &spec->hp_path,
+                                  &spec->hp_mix_path);
        }
-
-       return;
+       /* update speaker path */
+       update_aamix_paths(codec, val, &spec->speaker_path,
+                          &spec->speaker_mix_path);
+       return 1;
 }
 
-static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
+static const struct snd_kcontrol_new via_aamix_ctl_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Loopback Mixing",
+       .info = via_aamix_ctl_info,
+       .get = via_aamix_ctl_get,
+       .put = via_aamix_ctl_put,
+};
+
+static int via_auto_create_loopback_switch(struct hda_codec *codec)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
 
-       if (spec->codec_type != VT1708)
-               return 0;
-       spec->vt1708_jack_detectect =
-               !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
-       ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
+       if (!spec->aa_mix_nid || !spec->out_mix_path.depth)
+               return 0; /* no loopback switching available */
+       if (!via_clone_control(spec, &via_aamix_ctl_enum))
+               return -ENOMEM;
        return 0;
 }
 
-static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
+/* look for ADCs */
+static int via_fill_adcs(struct hda_codec *codec)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       int change;
+       hda_nid_t nid = codec->start_nid;
+       int i;
 
-       if (spec->codec_type != VT1708)
-               return 0;
-       spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
-       change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
-               == !spec->vt1708_jack_detectect;
-       if (spec->vt1708_jack_detectect) {
-               mute_aa_path(codec, 1);
-               notify_aa_path_ctls(codec);
+       for (i = 0; i < codec->num_nodes; i++, nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
+                       continue;
+               if (wcaps & AC_WCAP_DIGITAL)
+                       continue;
+               if (!(wcaps & AC_WCAP_CONN_LIST))
+                       continue;
+               if (spec->num_adc_nids >= ARRAY_SIZE(spec->adc_nids))
+                       return -ENOMEM;
+               spec->adc_nids[spec->num_adc_nids++] = nid;
        }
-       return change;
+       return 0;
 }
 
-static const struct snd_kcontrol_new vt1708_jack_detectect[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Jack Detect",
-               .count = 1,
-               .info = snd_ctl_boolean_mono_info,
-               .get = vt1708_jack_detectect_get,
-               .put = vt1708_jack_detectect_put,
-       },
-       {} /* end */
-};
-
-static int vt1708_parse_auto_config(struct hda_codec *codec)
+/* input-src control */
+static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info *uinfo)
 {
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       int err;
-
-       /* Add HP and CD pin config connect bit re-config action */
-       vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
-       vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-       if (err < 0)
-               return err;
-       err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
-               return 0; /* can't find valid BIOS pin config */
-
-       err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
-       if (err < 0)
-               return err;
-       err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       /* add jack detect on/off control */
-       err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       if (spec->autocfg.dig_outs)
-               spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
-       spec->dig_in_pin = VT1708_DIGIN_PIN;
-       if (spec->autocfg.dig_in_pin)
-               spec->dig_in_nid = VT1708_DIGIN_NID;
-
-       if (spec->kctls.list)
-               spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
-       spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
-
-       spec->input_mux = &spec->private_imux[0];
-
-       if (spec->hp_mux)
-               via_hp_build(codec);
-
-       via_smart51_build(spec);
-       return 1;
-}
-
-/* init callback for auto-configuration model -- overriding the default init */
-static int via_auto_init(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-
-       via_init(codec);
-       via_auto_init_multi_out(codec);
-       via_auto_init_hp_out(codec);
-       via_auto_init_analog_input(codec);
-
-       if (VT2002P_COMPATIBLE(spec)) {
-               via_hp_bind_automute(codec);
-       } else {
-               via_hp_automute(codec);
-               via_speaker_automute(codec);
-       }
-
-       return 0;
-}
-
-static void vt1708_update_hp_jack_state(struct work_struct *work)
-{
-       struct via_spec *spec = container_of(work, struct via_spec,
-                                            vt1708_hp_work.work);
-       if (spec->codec_type != VT1708)
-               return;
-       /* if jack state toggled */
-       if (spec->vt1708_hp_present
-           != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) {
-               spec->vt1708_hp_present ^= 1;
-               via_hp_automute(spec->codec);
-       }
-       vt1708_start_hp_work(spec);
-}
-
-static int get_mux_nids(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       hda_nid_t nid, conn[8];
-       unsigned int type;
-       int i, n;
-
-       for (i = 0; i < spec->num_adc_nids; i++) {
-               nid = spec->adc_nids[i];
-               while (nid) {
-                       type = get_wcaps_type(get_wcaps(codec, nid));
-                       if (type == AC_WID_PIN)
-                               break;
-                       n = snd_hda_get_connections(codec, nid, conn,
-                                                   ARRAY_SIZE(conn));
-                       if (n <= 0)
-                               break;
-                       if (n > 1) {
-                               spec->mux_nids[i] = nid;
-                               break;
-                       }
-                       nid = conn[0];
-               }
-       }
-       return 0;
-}
-
-static int patch_vt1708(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       /* automatic parse from the BIOS config */
-       err = vt1708_parse_auto_config(codec);
-       if (err < 0) {
-               via_free(codec);
-               return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration "
-                      "from BIOS.  Using genenic mode...\n");
-       }
-
-
-       spec->stream_name_analog = "VT1708 Analog";
-       spec->stream_analog_playback = &vt1708_pcm_analog_playback;
-       /* disable 32bit format on VT1708 */
-       if (codec->vendor_id == 0x11061708)
-               spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
-       spec->stream_analog_capture = &vt1708_pcm_analog_capture;
-
-       spec->stream_name_digital = "VT1708 Digital";
-       spec->stream_digital_playback = &vt1708_pcm_digital_playback;
-       spec->stream_digital_capture = &vt1708_pcm_digital_capture;
-
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1708_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
-               get_mux_nids(codec);
-               spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
-               spec->num_mixers++;
-       }
-
-       codec->patch_ops = via_patch_ops;
-
-       codec->patch_ops.init = via_auto_init;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1708_loopbacks;
-#endif
-       INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
-       return 0;
-}
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1709_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = via_mux_enum_info,
-               .get = via_mux_enum_get,
-               .put = via_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb vt1709_uniwill_init_verbs[] = {
-       {0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
-       { }
-};
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb vt1709_10ch_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
-       /*
-        * Set up output selector (0x1a, 0x1b, 0x29)
-        */
-       /* set vol=0 to output mixers */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /*
-        *  Unmute PW3 and PW4
-        */
-       {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* Set input of PW4 as MW0 */
-       {0x20, AC_VERB_SET_CONNECT_SEL, 0},
-       /* PW9 Output enable */
-       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       { }
-};
-
-static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 10,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-       },
-};
-
-static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 6,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-       },
-};
-
-static const struct hda_pcm_stream vt1709_pcm_analog_capture = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x14, /* NID to query formats and rates */
-       .ops = {
-               .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream vt1709_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in via_build_pcms */
-       .ops = {
-               .open = via_dig_playback_pcm_open,
-               .close = via_dig_playback_pcm_close
-       },
-};
-
-static const struct hda_pcm_stream vt1709_pcm_digital_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-};
-
-static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
-                                    const struct auto_pin_cfg *cfg)
-{
-       int i;
-       hda_nid_t nid;
-
-       if (cfg->line_outs == 4)  /* 10 channels */
-               spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
-       else if (cfg->line_outs == 3) /* 6 channels */
-               spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
-
-       spec->multiout.dac_nids = spec->private_dac_nids;
-
-       if (cfg->line_outs == 4) { /* 10 channels */
-               for (i = 0; i < cfg->line_outs; i++) {
-                       nid = cfg->line_out_pins[i];
-                       if (nid) {
-                               /* config dac list */
-                               switch (i) {
-                               case AUTO_SEQ_FRONT:
-                                       /* AOW0 */
-                                       spec->private_dac_nids[i] = 0x10;
-                                       break;
-                               case AUTO_SEQ_CENLFE:
-                                       /* AOW2 */
-                                       spec->private_dac_nids[i] = 0x12;
-                                       break;
-                               case AUTO_SEQ_SURROUND:
-                                       /* AOW3 */
-                                       spec->private_dac_nids[i] = 0x11;
-                                       break;
-                               case AUTO_SEQ_SIDE:
-                                       /* AOW1 */
-                                       spec->private_dac_nids[i] = 0x27;
-                                       break;
-                               default:
-                                       break;
-                               }
-                       }
-               }
-               spec->private_dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
-
-       } else if (cfg->line_outs == 3) { /* 6 channels */
-               for (i = 0; i < cfg->line_outs; i++) {
-                       nid = cfg->line_out_pins[i];
-                       if (nid) {
-                               /* config dac list */
-                               switch (i) {
-                               case AUTO_SEQ_FRONT:
-                                       /* AOW0 */
-                                       spec->private_dac_nids[i] = 0x10;
-                                       break;
-                               case AUTO_SEQ_CENLFE:
-                                       /* AOW2 */
-                                       spec->private_dac_nids[i] = 0x12;
-                                       break;
-                               case AUTO_SEQ_SURROUND:
-                                       /* AOW1 */
-                                       spec->private_dac_nids[i] = 0x11;
-                                       break;
-                               default:
-                                       break;
-                               }
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       char name[32];
-       static const char * const chname[4] = {
-               "Front", "Surround", "C/LFE", "Side"
-       };
-       hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
-       int i, err;
-
-       for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
-               nid = cfg->line_out_pins[i];
-
-               if (!nid)
-                       continue;
-
-               nid_vol = nid_vols[i];
-
-               if (i == AUTO_SEQ_CENLFE) {
-                       /* Center/LFE */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Center Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "LFE Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "Center Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "LFE Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else if (i == AUTO_SEQ_FRONT) {
-                       /* ADD control to mixer index 0 */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Master Front Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "Master Front Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
-
-                       /* add control to PW3 */
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else if (i == AUTO_SEQ_SURROUND) {
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else if (i == AUTO_SEQ_SIDE) {
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
-
-       return 0;
-}
-
-static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
-       int err;
-
-       if (!pin)
-               return 0;
-
-       if (spec->multiout.num_dacs == 5) /* 10 channels */
-               spec->multiout.hp_nid = VT1709_HP_DAC_NID;
-       else if (spec->multiout.num_dacs == 3) /* 6 channels */
-               spec->multiout.hp_nid = 0;
-       spec->hp_independent_mode_index = 1;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       static const hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
-       return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
-                                               ARRAY_SIZE(pin_idxs));
-}
-
-static int vt1709_parse_auto_config(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int err;
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-       if (err < 0)
-               return err;
-       err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
-               return 0; /* can't find valid BIOS pin config */
-
-       err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
-       if (err < 0)
-               return err;
-       err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       if (spec->autocfg.dig_outs)
-               spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
-       spec->dig_in_pin = VT1709_DIGIN_PIN;
-       if (spec->autocfg.dig_in_pin)
-               spec->dig_in_nid = VT1709_DIGIN_NID;
-
-       if (spec->kctls.list)
-               spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
-       spec->input_mux = &spec->private_imux[0];
-
-       if (spec->hp_mux)
-               via_hp_build(codec);
-
-       via_smart51_build(spec);
-       return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1709_loopbacks[] = {
-       { 0x18, HDA_INPUT, 1 },
-       { 0x18, HDA_INPUT, 2 },
-       { 0x18, HDA_INPUT, 3 },
-       { 0x18, HDA_INPUT, 4 },
-       { } /* end */
-};
-#endif
-
-static int patch_vt1709_10ch(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       err = vt1709_parse_auto_config(codec);
-       if (err < 0) {
-               via_free(codec);
-               return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration.  "
-                      "Using genenic mode...\n");
-       }
-
-       spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
-
-       spec->stream_name_analog = "VT1709 Analog";
-       spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1709_pcm_analog_capture;
-
-       spec->stream_name_digital = "VT1709 Digital";
-       spec->stream_digital_playback = &vt1709_pcm_digital_playback;
-       spec->stream_digital_capture = &vt1709_pcm_digital_capture;
-
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1709_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
-               get_mux_nids(codec);
-               spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
-               spec->num_mixers++;
-       }
-
-       codec->patch_ops = via_patch_ops;
-
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1709_loopbacks;
-#endif
-
-       return 0;
-}
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb vt1709_6ch_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
-       /*
-        * Set up output selector (0x1a, 0x1b, 0x29)
-        */
-       /* set vol=0 to output mixers */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /*
-        *  Unmute PW3 and PW4
-        */
-       {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* Set input of PW4 as MW0 */
-       {0x20, AC_VERB_SET_CONNECT_SEL, 0},
-       /* PW9 Output enable */
-       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       { }
-};
-
-static int patch_vt1709_6ch(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       err = vt1709_parse_auto_config(codec);
-       if (err < 0) {
-               via_free(codec);
-               return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration.  "
-                      "Using genenic mode...\n");
-       }
-
-       spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
-
-       spec->stream_name_analog = "VT1709 Analog";
-       spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1709_pcm_analog_capture;
-
-       spec->stream_name_digital = "VT1709 Digital";
-       spec->stream_digital_playback = &vt1709_pcm_digital_playback;
-       spec->stream_digital_capture = &vt1709_pcm_digital_capture;
-
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1709_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
-               get_mux_nids(codec);
-               spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
-               spec->num_mixers++;
-       }
-
-       codec->patch_ops = via_patch_ops;
-
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1709_loopbacks;
-#endif
-       return 0;
-}
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1708B_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = via_mux_enum_info,
-               .get = via_mux_enum_get,
-               .put = via_mux_enum_put,
-       },
-       { } /* end */
-};
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
-       /*
-        * Set up output mixers
-        */
-       /* set vol=0 to output mixers */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* Setup default input to PW4 */
-       {0x1d, AC_VERB_SET_CONNECT_SEL, 0},
-       /* PW9 Output enable */
-       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       /* PW10 Input enable */
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       { }
-};
-
-static const struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
-       /*
-        * Set up output mixers
-        */
-       /* set vol=0 to output mixers */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-       /* Setup default input of PW4 to MW0 */
-       {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* PW9 Output enable */
-       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       /* PW10 Input enable */
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       { }
-};
-
-static const struct hda_verb vt1708B_uniwill_init_verbs[] = {
-       {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
-       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       { }
-};
-
-static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
-                             struct hda_codec *codec,
-                             struct snd_pcm_substream *substream)
-{
-       int idle = substream->pstr->substream_opened == 1
-               && substream->ref_count == 0;
-
-       analog_low_current_mode(codec, idle);
-       return 0;
-}
-
-static const struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 8,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-               .close = via_pcm_open_close
-       },
-};
-
-static const struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 4,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream vt1708B_pcm_analog_capture = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x13, /* NID to query formats and rates */
-       .ops = {
-               .open = via_pcm_open_close,
-               .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup,
-               .close = via_pcm_open_close
-       },
-};
-
-static const struct hda_pcm_stream vt1708B_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in via_build_pcms */
-       .ops = {
-               .open = via_dig_playback_pcm_open,
-               .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare,
-               .cleanup = via_dig_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream vt1708B_pcm_digital_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
-                                    const struct auto_pin_cfg *cfg)
-{
-       int i;
-       hda_nid_t nid;
-
-       spec->multiout.num_dacs = cfg->line_outs;
-
-       spec->multiout.dac_nids = spec->private_dac_nids;
-
-       for (i = 0; i < 4; i++) {
-               nid = cfg->line_out_pins[i];
-               if (nid) {
-                       /* config dac list */
-                       switch (i) {
-                       case AUTO_SEQ_FRONT:
-                               spec->private_dac_nids[i] = 0x10;
-                               break;
-                       case AUTO_SEQ_CENLFE:
-                               spec->private_dac_nids[i] = 0x24;
-                               break;
-                       case AUTO_SEQ_SURROUND:
-                               spec->private_dac_nids[i] = 0x11;
-                               break;
-                       case AUTO_SEQ_SIDE:
-                               spec->private_dac_nids[i] = 0x25;
-                               break;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       char name[32];
-       static const char * const chname[4] = {
-               "Front", "Surround", "C/LFE", "Side"
-       };
-       hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
-       hda_nid_t nid, nid_vol = 0;
-       int i, err;
-
-       for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
-               nid = cfg->line_out_pins[i];
-
-               if (!nid)
-                       continue;
-
-               nid_vol = nid_vols[i];
-
-               if (i == AUTO_SEQ_CENLFE) {
-                       /* Center/LFE */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Center Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "LFE Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "Center Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "LFE Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else if (i == AUTO_SEQ_FRONT) {
-                       /* add control to mixer index 0 */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Master Front Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "Master Front Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
-
-                       /* add control to PW3 */
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
-
-       return 0;
-}
-
-static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
-       int err;
-
-       if (!pin)
-               return 0;
-
-       spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
-       spec->hp_independent_mode_index = 1;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-
-       create_hp_imux(spec);
-
-       return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       static const hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
-       return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
-                                               ARRAY_SIZE(pin_idxs));
-}
-
-static int vt1708B_parse_auto_config(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int err;
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-       if (err < 0)
-               return err;
-       err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
-               return 0; /* can't find valid BIOS pin config */
-
-       err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
-       if (err < 0)
-               return err;
-       err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       if (spec->autocfg.dig_outs)
-               spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
-       spec->dig_in_pin = VT1708B_DIGIN_PIN;
-       if (spec->autocfg.dig_in_pin)
-               spec->dig_in_nid = VT1708B_DIGIN_NID;
-
-       if (spec->kctls.list)
-               spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
-       spec->input_mux = &spec->private_imux[0];
-
-       if (spec->hp_mux)
-               via_hp_build(codec);
-
-       via_smart51_build(spec);
-       return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1708B_loopbacks[] = {
-       { 0x16, HDA_INPUT, 1 },
-       { 0x16, HDA_INPUT, 2 },
-       { 0x16, HDA_INPUT, 3 },
-       { 0x16, HDA_INPUT, 4 },
-       { } /* end */
-};
-#endif
-
-static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int imux_is_smixer;
-       unsigned int parm;
-       int is_8ch = 0;
-       if ((spec->codec_type != VT1708B_4CH) &&
-           (codec->vendor_id != 0x11064397))
-               is_8ch = 1;
-
-       /* SW0 (17h) = stereo mixer */
-       imux_is_smixer =
-       (snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
-        == ((spec->codec_type == VT1708S) ? 5 : 0));
-       /* inputs */
-       /* PW 1/2/5 (1ah/1bh/1eh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x1a, &parm);
-       set_pin_power_state(codec, 0x1b, &parm);
-       set_pin_power_state(codec, 0x1e, &parm);
-       if (imux_is_smixer)
-               parm = AC_PWRST_D0;
-       /* SW0 (17h), AIW 0/1 (13h/14h) */
-       snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
-       snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
-       snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
-
-       /* outputs */
-       /* PW0 (19h), SW1 (18h), AOW1 (11h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x19, &parm);
-       if (spec->smart51_enabled)
-               set_pin_power_state(codec, 0x1b, &parm);
-       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
-       snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
-
-       /* PW6 (22h), SW2 (26h), AOW2 (24h) */
-       if (is_8ch) {
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x22, &parm);
-               if (spec->smart51_enabled)
-                       set_pin_power_state(codec, 0x1a, &parm);
-               snd_hda_codec_write(codec, 0x26, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x24, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-       } else if (codec->vendor_id == 0x11064397) {
-               /* PW7(23h), SW2(27h), AOW2(25h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x23, &parm);
-               if (spec->smart51_enabled)
-                       set_pin_power_state(codec, 0x1a, &parm);
-               snd_hda_codec_write(codec, 0x27, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x25, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-       }
-
-       /* PW 3/4/7 (1ch/1dh/23h) */
-       parm = AC_PWRST_D3;
-       /* force to D0 for internal Speaker */
-       set_pin_power_state(codec, 0x1c, &parm);
-       set_pin_power_state(codec, 0x1d, &parm);
-       if (is_8ch)
-               set_pin_power_state(codec, 0x23, &parm);
-
-       /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
-       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
-                           imux_is_smixer ? AC_PWRST_D0 : parm);
-       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
-       if (is_8ch) {
-               snd_hda_codec_write(codec, 0x25, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-               snd_hda_codec_write(codec, 0x27, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-       } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode)
-               snd_hda_codec_write(codec, 0x25, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-}
-
-static int patch_vt1708S(struct hda_codec *codec);
-static int patch_vt1708B_8ch(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       if (get_codec_type(codec) == VT1708BCE)
-               return patch_vt1708S(codec);
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       /* automatic parse from the BIOS config */
-       err = vt1708B_parse_auto_config(codec);
-       if (err < 0) {
-               via_free(codec);
-               return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration "
-                      "from BIOS.  Using genenic mode...\n");
-       }
-
-       spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
-
-       spec->stream_name_analog = "VT1708B Analog";
-       spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
-
-       spec->stream_name_digital = "VT1708B Digital";
-       spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
-       spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1708B_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
-               get_mux_nids(codec);
-               spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
-               spec->num_mixers++;
-       }
-
-       codec->patch_ops = via_patch_ops;
-
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1708B_loopbacks;
-#endif
-
-       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
-
-       return 0;
-}
-
-static int patch_vt1708B_4ch(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       /* automatic parse from the BIOS config */
-       err = vt1708B_parse_auto_config(codec);
-       if (err < 0) {
-               via_free(codec);
-               return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration "
-                      "from BIOS.  Using genenic mode...\n");
-       }
-
-       spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
-
-       spec->stream_name_analog = "VT1708B Analog";
-       spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
-
-       spec->stream_name_digital = "VT1708B Digital";
-       spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
-       spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1708B_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
-               get_mux_nids(codec);
-               spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
-               spec->num_mixers++;
-       }
-
-       codec->patch_ops = via_patch_ops;
-
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1708B_loopbacks;
-#endif
-
-       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
 
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = spec->num_inputs;
+       if (uinfo->value.enumerated.item >= spec->num_inputs)
+               uinfo->value.enumerated.item = spec->num_inputs - 1;
+       strcpy(uinfo->value.enumerated.name,
+              spec->inputs[uinfo->value.enumerated.item].label);
        return 0;
 }
 
-/* Patch for VT1708S */
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1708S_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
-                        HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = via_mux_enum_info,
-               .get = via_mux_enum_get,
-               .put = via_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb vt1708S_volume_init_verbs[] = {
-       /* Unmute ADC0-1 and set the default input to mic-in */
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
-        * analog-loopback mixer widget */
-       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
-       /* Setup default input of PW4 to MW0 */
-       {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* PW9, PW10  Output enable */
-       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       /* Enable Mic Boost Volume backdoor */
-       {0x1, 0xf98, 0x1},
-       /* don't bybass mixer */
-       {0x1, 0xf88, 0xc0},
-       { }
-};
-
-static const struct hda_verb vt1708S_uniwill_init_verbs[] = {
-       {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
-       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       { }
-};
-
-static const struct hda_verb vt1705_uniwill_init_verbs[] = {
-       {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
-       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       { }
-};
-
-static const struct hda_pcm_stream vt1708S_pcm_analog_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 8,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-               .close = via_pcm_open_close
-       },
-};
-
-static const struct hda_pcm_stream vt1705_pcm_analog_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 6,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-               .close = via_pcm_open_close
-       },
-};
-
-static const struct hda_pcm_stream vt1708S_pcm_analog_capture = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x13, /* NID to query formats and rates */
-       .ops = {
-               .open = via_pcm_open_close,
-               .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup,
-               .close = via_pcm_open_close
-       },
-};
-
-static const struct hda_pcm_stream vt1708S_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in via_build_pcms */
-       .ops = {
-               .open = via_dig_playback_pcm_open,
-               .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare,
-               .cleanup = via_dig_playback_pcm_cleanup
-       },
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
-                                    const struct auto_pin_cfg *cfg)
+static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
 {
-       int i;
-       hda_nid_t nid;
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 
-       spec->multiout.num_dacs = cfg->line_outs;
+       ucontrol->value.enumerated.item[0] = spec->cur_mux[idx];
+       return 0;
+}
 
-       spec->multiout.dac_nids = spec->private_dac_nids;
+static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       hda_nid_t mux;
+       int cur;
 
-       for (i = 0; i < 4; i++) {
-               nid = cfg->line_out_pins[i];
-               if (nid) {
-                       /* config dac list */
-                       switch (i) {
-                       case AUTO_SEQ_FRONT:
-                               spec->private_dac_nids[i] = 0x10;
-                               break;
-                       case AUTO_SEQ_CENLFE:
-                               if (spec->codec->vendor_id == 0x11064397)
-                                       spec->private_dac_nids[i] = 0x25;
-                               else
-                                       spec->private_dac_nids[i] = 0x24;
-                               break;
-                       case AUTO_SEQ_SURROUND:
-                               spec->private_dac_nids[i] = 0x11;
-                               break;
-                       case AUTO_SEQ_SIDE:
-                               spec->private_dac_nids[i] = 0x25;
-                               break;
-                       }
-               }
+       cur = ucontrol->value.enumerated.item[0];
+       if (cur < 0 || cur >= spec->num_inputs)
+               return -EINVAL;
+       if (spec->cur_mux[idx] == cur)
+               return 0;
+       spec->cur_mux[idx] = cur;
+       if (spec->dyn_adc_switch) {
+               int adc_idx = spec->inputs[cur].adc_idx;
+               mux = spec->mux_nids[adc_idx];
+               via_dyn_adc_pcm_resetup(codec, cur);
+       } else {
+               mux = spec->mux_nids[idx];
+               if (snd_BUG_ON(!mux))
+                       return -EINVAL;
        }
 
-       /* for Smart 5.1, line/mic inputs double as output pins */
-       if (cfg->line_outs == 1) {
-               spec->multiout.num_dacs = 3;
-               spec->private_dac_nids[AUTO_SEQ_SURROUND] = 0x11;
-               if (spec->codec->vendor_id == 0x11064397)
-                       spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x25;
-               else
-                       spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x24;
+       if (mux) {
+               /* switch to D0 beofre change index */
+               if (snd_hda_codec_read(codec, mux, 0,
+                              AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
+                       snd_hda_codec_write(codec, mux, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+               snd_hda_codec_write(codec, mux, 0,
+                                   AC_VERB_SET_CONNECT_SEL,
+                                   spec->inputs[cur].mux_idx);
        }
 
+       /* update jack power state */
+       set_widgets_power_state(codec);
        return 0;
 }
 
-/* add playback controls from the parsed DAC table */
-static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec,
-                                            const struct auto_pin_cfg *cfg)
+static const struct snd_kcontrol_new via_input_src_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       /* The multiple "Capture Source" controls confuse alsamixer
+        * So call somewhat different..
+        */
+       /* .name = "Capture Source", */
+       .name = "Input Source",
+       .info = via_mux_enum_info,
+       .get = via_mux_enum_get,
+       .put = via_mux_enum_put,
+};
+
+static int create_input_src_ctls(struct hda_codec *codec, int count)
 {
        struct via_spec *spec = codec->spec;
-       char name[32];
-       static const char * const chname[4] = {
-               "Front", "Surround", "C/LFE", "Side"
-       };
-       hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25},
-                                    {0x10, 0x11, 0x25, 0} };
-       hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27},
-                                     {0x1C, 0x18, 0x27, 0} };
-       hda_nid_t nid, nid_vol, nid_mute;
-       int i, err;
-
-       for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
-               nid = cfg->line_out_pins[i];
-
-               /* for Smart 5.1, there are always at least six channels */
-               if (!nid && i > AUTO_SEQ_CENLFE)
-                       continue;
-
-               if (codec->vendor_id == 0x11064397) {
-                       nid_vol = nid_vols[1][i];
-                       nid_mute = nid_mutes[1][i];
-               } else {
-                       nid_vol = nid_vols[0][i];
-                       nid_mute = nid_mutes[0][i];
-               }
-               if (!nid_vol && !nid_mute)
-                       continue;
-
-               if (i == AUTO_SEQ_CENLFE) {
-                       /* Center/LFE */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Center Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "LFE Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "Center Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_mute,
-                                                                 1, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "LFE Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_mute,
-                                                                 2, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else if (i == AUTO_SEQ_FRONT) {
-                       /* add control to mixer index 0 */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Master Front Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "Master Front Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
+       struct snd_kcontrol_new *knew;
 
-                       /* Front */
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_mute,
-                                                                 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_mute,
-                                                                 3, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
+       if (spec->num_inputs <= 1 || !count)
+               return 0; /* no need for single src */
 
+       knew = via_clone_control(spec, &via_input_src_ctl);
+       if (!knew)
+               return -ENOMEM;
+       knew->count = count;
        return 0;
 }
 
-static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+/* add the powersave loopback-list entry */
+static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx)
 {
-       int err;
-
-       if (!pin)
-               return 0;
-
-       spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
-       spec->hp_independent_mode_index = 1;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
+       struct hda_amp_list *list;
 
-       create_hp_imux(spec);
-
-       return 0;
+       if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1)
+               return;
+       list = spec->loopback_list + spec->num_loopbacks;
+       list->nid = mix;
+       list->dir = HDA_INPUT;
+       list->idx = idx;
+       spec->num_loopbacks++;
+       spec->loopback.amplist = spec->loopback_list;
 }
 
-/* create playback/capture controls for input pins */
-static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
+static bool is_reachable_nid(struct hda_codec *codec, hda_nid_t src,
+                            hda_nid_t dst)
 {
-       static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
-       return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
-                                               ARRAY_SIZE(pin_idxs));
+       return snd_hda_get_conn_index(codec, src, dst, 1) >= 0;
 }
 
-/* fill out digital output widgets; one for master and one for slave outputs */
-static void fill_dig_outs(struct hda_codec *codec)
+/* add the input-route to the given pin */
+static bool add_input_route(struct hda_codec *codec, hda_nid_t pin)
 {
        struct via_spec *spec = codec->spec;
-       int i;
+       int c, idx;
 
-       for (i = 0; i < spec->autocfg.dig_outs; i++) {
-               hda_nid_t nid;
-               int conn;
-
-               nid = spec->autocfg.dig_out_pins[i];
-               if (!nid)
-                       continue;
-               conn = snd_hda_get_connections(codec, nid, &nid, 1);
-               if (conn < 1)
-                       continue;
-               if (!spec->multiout.dig_out_nid)
-                       spec->multiout.dig_out_nid = nid;
-               else {
-                       spec->slave_dig_outs[0] = nid;
-                       break; /* at most two dig outs */
+       spec->inputs[spec->num_inputs].adc_idx = -1;
+       spec->inputs[spec->num_inputs].pin = pin;
+       for (c = 0; c < spec->num_adc_nids; c++) {
+               if (spec->mux_nids[c]) {
+                       idx = get_connection_index(codec, spec->mux_nids[c],
+                                                  pin);
+                       if (idx < 0)
+                               continue;
+                       spec->inputs[spec->num_inputs].mux_idx = idx;
+               } else {
+                       if (!is_reachable_nid(codec, spec->adc_nids[c], pin))
+                               continue;
                }
+               spec->inputs[spec->num_inputs].adc_idx = c;
+               /* Can primary ADC satisfy all inputs? */
+               if (!spec->dyn_adc_switch &&
+                   spec->num_inputs > 0 && spec->inputs[0].adc_idx != c) {
+                       snd_printd(KERN_INFO
+                                  "via: dynamic ADC switching enabled\n");
+                       spec->dyn_adc_switch = 1;
+               }
+               return true;
        }
+       return false;
 }
 
-static int vt1708S_parse_auto_config(struct hda_codec *codec)
+static int get_mux_nids(struct hda_codec *codec);
+
+/* parse input-routes; fill ADCs, MUXs and input-src entries */
+static int parse_analog_inputs(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
-       int err;
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-       if (err < 0)
-               return err;
-       err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
-               return 0; /* can't find valid BIOS pin config */
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, err;
 
-       err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       err = via_fill_adcs(codec);
        if (err < 0)
                return err;
-       err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg);
+       err = get_mux_nids(codec);
        if (err < 0)
                return err;
 
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       fill_dig_outs(codec);
-
-       if (spec->kctls.list)
-               spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
-       spec->input_mux = &spec->private_imux[0];
-
-       if (spec->hp_mux)
-               via_hp_build(codec);
-
-       via_smart51_build(spec);
-       return 1;
-}
+       /* fill all input-routes */
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (add_input_route(codec, cfg->inputs[i].pin))
+                       spec->inputs[spec->num_inputs++].label =
+                               hda_get_autocfg_input_label(codec, cfg, i);
+       }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1708S_loopbacks[] = {
-       { 0x16, HDA_INPUT, 1 },
-       { 0x16, HDA_INPUT, 2 },
-       { 0x16, HDA_INPUT, 3 },
-       { 0x16, HDA_INPUT, 4 },
-       { } /* end */
-};
-#endif
+       /* check for internal loopback recording */
+       if (spec->aa_mix_nid &&
+           add_input_route(codec, spec->aa_mix_nid))
+               spec->inputs[spec->num_inputs++].label = "Stereo Mixer";
 
-static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
-                              int offset, int num_steps, int step_size)
-{
-       snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
-                                 (offset << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (0 << AC_AMPCAP_MUTE_SHIFT));
+       return 0;
 }
 
-static int patch_vt1708S(struct hda_codec *codec)
+/* create analog-loopback volume/switch controls */
+static int create_loopback_ctls(struct hda_codec *codec)
 {
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
+       struct via_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       const char *prev_label = NULL;
+       int type_idx = 0;
+       int i, j, err, idx;
 
-       /* automatic parse from the BIOS config */
-       err = vt1708S_parse_auto_config(codec);
-       if (err < 0) {
-               via_free(codec);
-               return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration "
-                      "from BIOS.  Using genenic mode...\n");
-       }
+       if (!spec->aa_mix_nid)
+               return 0;
 
-       spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
-       if (codec->vendor_id == 0x11064397)
-               spec->init_verbs[spec->num_iverbs++] =
-                       vt1705_uniwill_init_verbs;
-       else
-               spec->init_verbs[spec->num_iverbs++] =
-                       vt1708S_uniwill_init_verbs;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t pin = cfg->inputs[i].pin;
+               const char *label = hda_get_autocfg_input_label(codec, cfg, i);
 
-       if (codec->vendor_id == 0x11060440)
-               spec->stream_name_analog = "VT1818S Analog";
-       else if (codec->vendor_id == 0x11064397)
-               spec->stream_name_analog = "VT1705 Analog";
-       else
-               spec->stream_name_analog = "VT1708S Analog";
-       if (codec->vendor_id == 0x11064397)
-               spec->stream_analog_playback = &vt1705_pcm_analog_playback;
-       else
-               spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
+               if (prev_label && !strcmp(label, prev_label))
+                       type_idx++;
+               else
+                       type_idx = 0;
+               prev_label = label;
+               idx = get_connection_index(codec, spec->aa_mix_nid, pin);
+               if (idx >= 0) {
+                       err = via_new_analog_input(spec, label, type_idx,
+                                                  idx, spec->aa_mix_nid);
+                       if (err < 0)
+                               return err;
+                       add_loopback_list(spec, spec->aa_mix_nid, idx);
+               }
 
-       if (codec->vendor_id == 0x11060440)
-               spec->stream_name_digital = "VT1818S Digital";
-       else if (codec->vendor_id == 0x11064397)
-               spec->stream_name_digital = "VT1705 Digital";
-       else
-               spec->stream_name_digital = "VT1708S Digital";
-       spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1708S_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
-               get_mux_nids(codec);
-               override_mic_boost(codec, 0x1a, 0, 3, 40);
-               override_mic_boost(codec, 0x1e, 0, 3, 40);
-               spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
-               spec->num_mixers++;
+               /* remember the label for smart51 control */
+               for (j = 0; j < spec->smart51_nums; j++) {
+                       if (spec->smart51_pins[j] == pin) {
+                               spec->smart51_idxs[j] = idx;
+                               spec->smart51_labels[j] = label;
+                               break;
+                       }
+               }
        }
+       return 0;
+}
 
-       codec->patch_ops = via_patch_ops;
+/* create mic-boost controls (if present) */
+static int create_mic_boost_ctls(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, err;
 
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1708S_loopbacks;
-#endif
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t pin = cfg->inputs[i].pin;
+               unsigned int caps;
+               const char *label;
+               char name[32];
 
-       /* correct names for VT1708BCE */
-       if (get_codec_type(codec) == VT1708BCE) {
-               kfree(codec->chip_name);
-               codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
-               snprintf(codec->bus->card->mixername,
-                        sizeof(codec->bus->card->mixername),
-                        "%s %s", codec->vendor_name, codec->chip_name);
-               spec->stream_name_analog = "VT1708BCE Analog";
-               spec->stream_name_digital = "VT1708BCE Digital";
-       }
-       /* correct names for VT1818S */
-       if (codec->vendor_id == 0x11060440) {
-               spec->stream_name_analog = "VT1818S Analog";
-               spec->stream_name_digital = "VT1818S Digital";
-       }
-       /* correct names for VT1705 */
-       if (codec->vendor_id == 0x11064397)     {
-               kfree(codec->chip_name);
-               codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
-               snprintf(codec->bus->card->mixername,
-                        sizeof(codec->bus->card->mixername),
-                        "%s %s", codec->vendor_name, codec->chip_name);
+               if (cfg->inputs[i].type != AUTO_PIN_MIC)
+                       continue;
+               caps = query_amp_caps(codec, pin, HDA_INPUT);
+               if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS))
+                       continue;
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               snprintf(name, sizeof(name), "%s Boost Volume", label);
+               err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT));
+               if (err < 0)
+                       return err;
        }
-       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
        return 0;
 }
 
-/* Patch for VT1702 */
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1702_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
-                        HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = via_mux_enum_info,
-               .get = via_mux_enum_get,
-               .put = via_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb vt1702_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /* Setup default input of PW4 to MW0 */
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* PW6 PW7 Output enable */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       /* mixer enable */
-       {0x1, 0xF88, 0x3},
-       /* GPIO 0~2 */
-       {0x1, 0xF82, 0x3F},
-       { }
-};
-
-static const struct hda_verb vt1702_uniwill_init_verbs[] = {
-       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       { }
-};
+/* create capture and input-src controls for multiple streams */
+static int create_multi_adc_ctls(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int i, err;
 
-static const struct hda_pcm_stream vt1702_pcm_analog_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-               .close = via_pcm_open_close
-       },
-};
+       /* create capture mixer elements */
+       for (i = 0; i < spec->num_adc_nids; i++) {
+               hda_nid_t adc = spec->adc_nids[i];
+               err = __via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                       "Capture Volume", i,
+                                       HDA_COMPOSE_AMP_VAL(adc, 3, 0,
+                                                           HDA_INPUT));
+               if (err < 0)
+                       return err;
+               err = __via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                                       "Capture Switch", i,
+                                       HDA_COMPOSE_AMP_VAL(adc, 3, 0,
+                                                           HDA_INPUT));
+               if (err < 0)
+                       return err;
+       }
 
-static const struct hda_pcm_stream vt1702_pcm_analog_capture = {
-       .substreams = 3,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x12, /* NID to query formats and rates */
-       .ops = {
-               .open = via_pcm_open_close,
-               .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup,
-               .close = via_pcm_open_close
-       },
-};
+       /* input-source control */
+       for (i = 0; i < spec->num_adc_nids; i++)
+               if (!spec->mux_nids[i])
+                       break;
+       err = create_input_src_ctls(codec, i);
+       if (err < 0)
+               return err;
+       return 0;
+}
 
-static const struct hda_pcm_stream vt1702_pcm_digital_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in via_build_pcms */
-       .ops = {
-               .open = via_dig_playback_pcm_open,
-               .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare,
-               .cleanup = via_dig_playback_pcm_cleanup
-       },
-};
+/* bind capture volume/switch */
+static struct snd_kcontrol_new via_bind_cap_vol_ctl =
+       HDA_BIND_VOL("Capture Volume", 0);
+static struct snd_kcontrol_new via_bind_cap_sw_ctl =
+       HDA_BIND_SW("Capture Switch", 0);
 
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
-                                    const struct auto_pin_cfg *cfg)
+static int init_bind_ctl(struct via_spec *spec, struct hda_bind_ctls **ctl_ret,
+                        struct hda_ctl_ops *ops)
 {
-       spec->multiout.num_dacs = 1;
-       spec->multiout.dac_nids = spec->private_dac_nids;
-
-       if (cfg->line_out_pins[0]) {
-               /* config dac list */
-               spec->private_dac_nids[0] = 0x10;
-       }
+       struct hda_bind_ctls *ctl;
+       int i;
 
+       ctl = kzalloc(sizeof(*ctl) + sizeof(long) * 4, GFP_KERNEL);
+       if (!ctl)
+               return -ENOMEM;
+       ctl->ops = ops;
+       for (i = 0; i < spec->num_adc_nids; i++)
+               ctl->values[i] =
+                       HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], 3, 0, HDA_INPUT);
+       *ctl_ret = ctl;
        return 0;
 }
 
-/* add playback controls from the parsed DAC table */
-static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
+/* create capture and input-src controls for dynamic ADC-switch case */
+static int create_dyn_adc_ctls(struct hda_codec *codec)
 {
+       struct via_spec *spec = codec->spec;
+       struct snd_kcontrol_new *knew;
        int err;
 
-       if (!cfg->line_out_pins[0])
-               return -1;
-
-       /* add control to mixer index 0 */
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Master Front Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
+       /* set up the bind capture ctls */
+       err = init_bind_ctl(spec, &spec->bind_cap_vol, &snd_hda_bind_vol);
        if (err < 0)
                return err;
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Master Front Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
+       err = init_bind_ctl(spec, &spec->bind_cap_sw, &snd_hda_bind_sw);
        if (err < 0)
                return err;
 
-       /* Front */
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Front Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Front Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
+       /* create capture mixer elements */
+       knew = via_clone_control(spec, &via_bind_cap_vol_ctl);
+       if (!knew)
+               return -ENOMEM;
+       knew->private_value = (long)spec->bind_cap_vol;
+
+       knew = via_clone_control(spec, &via_bind_cap_sw_ctl);
+       if (!knew)
+               return -ENOMEM;
+       knew->private_value = (long)spec->bind_cap_sw;
+
+       /* input-source control */
+       err = create_input_src_ctls(codec, 1);
        if (err < 0)
                return err;
-
        return 0;
 }
 
-static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+/* parse and create capture-related stuff */
+static int via_auto_create_analog_input_ctls(struct hda_codec *codec)
 {
-       int err, i;
-       struct hda_input_mux *imux;
-       static const char * const texts[] = { "ON", "OFF", NULL};
-       if (!pin)
-               return 0;
-       spec->multiout.hp_nid = 0x1D;
-       spec->hp_independent_mode_index = 0;
+       struct via_spec *spec = codec->spec;
+       int err;
 
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
+       err = parse_analog_inputs(codec);
        if (err < 0)
                return err;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       if (spec->dyn_adc_switch)
+               err = create_dyn_adc_ctls(codec);
+       else
+               err = create_multi_adc_ctls(codec);
+       if (err < 0)
+               return err;
+       err = create_loopback_ctls(codec);
+       if (err < 0)
+               return err;
+       err = create_mic_boost_ctls(codec);
        if (err < 0)
                return err;
+       return 0;
+}
+
+static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int def_conf;
+       unsigned char seqassoc;
+
+       def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       seqassoc = (unsigned char) get_defcfg_association(def_conf);
+       seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
+       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
+           && (seqassoc == 0xf0 || seqassoc == 0xff)) {
+               def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
+               snd_hda_codec_set_pincfg(codec, nid, def_conf);
+       }
 
-       imux = &spec->private_imux[1];
+       return;
+}
 
-       /* for hp mode select */
-       for (i = 0; texts[i]; i++)
-               snd_hda_add_imux_item(imux, texts[i], i, NULL);
+static int vt1708_jack_detect_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
 
-       spec->hp_mux = &spec->private_imux[1];
+       if (spec->codec_type != VT1708)
+               return 0;
+       spec->vt1708_jack_detect =
+               !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
+       ucontrol->value.integer.value[0] = spec->vt1708_jack_detect;
        return 0;
 }
 
-/* create playback/capture controls for input pins */
-static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
+static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
 {
-       static const hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
-       return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
-                                               ARRAY_SIZE(pin_idxs));
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       int change;
+
+       if (spec->codec_type != VT1708)
+               return 0;
+       spec->vt1708_jack_detect = ucontrol->value.integer.value[0];
+       change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
+               == !spec->vt1708_jack_detect;
+       if (spec->vt1708_jack_detect) {
+               mute_aa_path(codec, 1);
+               notify_aa_path_ctls(codec);
+       }
+       return change;
 }
 
-static int vt1702_parse_auto_config(struct hda_codec *codec)
+static const struct snd_kcontrol_new vt1708_jack_detect_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Jack Detect",
+       .count = 1,
+       .info = snd_ctl_boolean_mono_info,
+       .get = vt1708_jack_detect_get,
+       .put = vt1708_jack_detect_put,
+};
+
+static void fill_dig_outs(struct hda_codec *codec);
+static void fill_dig_in(struct hda_codec *codec);
+
+static int via_parse_auto_config(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        int err;
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-       if (err < 0)
-               return err;
-       err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
        if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
-               return 0; /* can't find valid BIOS pin config */
+               return -EINVAL;
 
-       err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
+       err = via_auto_create_multi_out_ctls(codec);
        if (err < 0)
                return err;
-       err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       err = via_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       /* limit AA path volume to 0 dB */
-       snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
-                                 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (1 << AC_AMPCAP_MUTE_SHIFT));
-       err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg);
+       err = via_auto_create_speaker_ctls(codec);
+       if (err < 0)
+               return err;
+       err = via_auto_create_loopback_switch(codec);
+       if (err < 0)
+               return err;
+       err = via_auto_create_analog_input_ctls(codec);
        if (err < 0)
                return err;
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
        fill_dig_outs(codec);
+       fill_dig_in(codec);
 
        if (spec->kctls.list)
                spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
-       spec->input_mux = &spec->private_imux[0];
 
-       if (spec->hp_mux)
-               via_hp_build(codec);
+       if (spec->hp_dac_nid && spec->hp_mix_path.depth) {
+               err = via_hp_build(codec);
+               if (err < 0)
+                       return err;
+       }
+
+       err = via_smart51_build(codec);
+       if (err < 0)
+               return err;
+
+       /* assign slave outs */
+       if (spec->slave_dig_outs[0])
+               codec->slave_dig_outs = spec->slave_dig_outs;
 
        return 1;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1702_loopbacks[] = {
-       { 0x1A, HDA_INPUT, 1 },
-       { 0x1A, HDA_INPUT, 2 },
-       { 0x1A, HDA_INPUT, 3 },
-       { 0x1A, HDA_INPUT, 4 },
-       { } /* end */
-};
-#endif
+static void via_auto_init_dig_outs(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       if (spec->multiout.dig_out_nid)
+               init_output_pin(codec, spec->autocfg.dig_out_pins[0], PIN_OUT);
+       if (spec->slave_dig_outs[0])
+               init_output_pin(codec, spec->autocfg.dig_out_pins[1], PIN_OUT);
+}
 
-static void set_widgets_power_state_vt1702(struct hda_codec *codec)
+static void via_auto_init_dig_in(struct hda_codec *codec)
 {
-       int imux_is_smixer =
-       snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+       struct via_spec *spec = codec->spec;
+       if (!spec->dig_in_nid)
+               return;
+       snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+}
+
+/* initialize the unsolicited events */
+static void via_auto_init_unsol_event(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int ev;
+       int i;
+
+       if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0]))
+               snd_hda_codec_write(codec, cfg->hp_pins[0], 0,
+                               AC_VERB_SET_UNSOLICITED_ENABLE,
+                               AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT);
+
+       if (cfg->speaker_pins[0])
+               ev = VIA_LINE_EVENT;
+       else
+               ev = 0;
+       for (i = 0; i < cfg->line_outs; i++) {
+               if (cfg->line_out_pins[i] &&
+                   is_jack_detectable(codec, cfg->line_out_pins[i]))
+                       snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
+                               AC_VERB_SET_UNSOLICITED_ENABLE,
+                               AC_USRSP_EN | ev | VIA_JACK_EVENT);
+       }
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (is_jack_detectable(codec, cfg->inputs[i].pin))
+                       snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
+                               AC_VERB_SET_UNSOLICITED_ENABLE,
+                               AC_USRSP_EN | VIA_JACK_EVENT);
+       }
+}
+
+static int via_init(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < spec->num_iverbs; i++)
+               snd_hda_sequence_write(codec, spec->init_verbs[i]);
+
+       via_auto_init_multi_out(codec);
+       via_auto_init_hp_out(codec);
+       via_auto_init_speaker_out(codec);
+       via_auto_init_analog_input(codec);
+       via_auto_init_dig_outs(codec);
+       via_auto_init_dig_in(codec);
+
+       via_auto_init_unsol_event(codec);
+
+       via_hp_automute(codec);
+
+       return 0;
+}
+
+static void vt1708_update_hp_jack_state(struct work_struct *work)
+{
+       struct via_spec *spec = container_of(work, struct via_spec,
+                                            vt1708_hp_work.work);
+       if (spec->codec_type != VT1708)
+               return;
+       /* if jack state toggled */
+       if (spec->vt1708_hp_present
+           != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) {
+               spec->vt1708_hp_present ^= 1;
+               via_hp_automute(spec->codec);
+       }
+       vt1708_start_hp_work(spec);
+}
+
+static int get_mux_nids(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       hda_nid_t nid, conn[8];
+       unsigned int type;
+       int i, n;
+
+       for (i = 0; i < spec->num_adc_nids; i++) {
+               nid = spec->adc_nids[i];
+               while (nid) {
+                       type = get_wcaps_type(get_wcaps(codec, nid));
+                       if (type == AC_WID_PIN)
+                               break;
+                       n = snd_hda_get_connections(codec, nid, conn,
+                                                   ARRAY_SIZE(conn));
+                       if (n <= 0)
+                               break;
+                       if (n > 1) {
+                               spec->mux_nids[i] = nid;
+                               break;
+                       }
+                       nid = conn[0];
+               }
+       }
+       return 0;
+}
+
+static int patch_vt1708(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->aa_mix_nid = 0x17;
+
+       /* Add HP and CD pin config connect bit re-config action */
+       vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
+       vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       }
+
+       /* add jack detect on/off control */
+       if (!via_clone_control(spec, &vt1708_jack_detect_ctl))
+               return -ENOMEM;
+
+       /* disable 32bit format on VT1708 */
+       if (codec->vendor_id == 0x11061708)
+               spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
+
+       spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs;
+
+       codec->patch_ops = via_patch_ops;
+
+       INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
+       return 0;
+}
+
+static int patch_vt1709(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->aa_mix_nid = 0x18;
+
+       err = via_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       }
+
+       codec->patch_ops = via_patch_ops;
+
+       return 0;
+}
+
+static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int imux_is_smixer;
        unsigned int parm;
+       int is_8ch = 0;
+       if ((spec->codec_type != VT1708B_4CH) &&
+           (codec->vendor_id != 0x11064397))
+               is_8ch = 1;
+
+       /* SW0 (17h) = stereo mixer */
+       imux_is_smixer =
+       (snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
+        == ((spec->codec_type == VT1708S) ? 5 : 0));
        /* inputs */
-       /* PW 1/2/5 (14h/15h/18h) */
+       /* PW 1/2/5 (1ah/1bh/1eh) */
        parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x14, &parm);
-       set_pin_power_state(codec, 0x15, &parm);
-       set_pin_power_state(codec, 0x18, &parm);
+       set_pin_power_state(codec, 0x1a, &parm);
+       set_pin_power_state(codec, 0x1b, &parm);
+       set_pin_power_state(codec, 0x1e, &parm);
        if (imux_is_smixer)
-               parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */
-       /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
+               parm = AC_PWRST_D0;
+       /* SW0 (17h), AIW 0/1 (13h/14h) */
+       snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
        snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
-       snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm);
-       snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
 
        /* outputs */
-       /* PW 3/4 (16h/17h) */
+       /* PW0 (19h), SW1 (18h), AOW1 (11h) */
        parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x17, &parm);
-       set_pin_power_state(codec, 0x16, &parm);
-       /* MW0 (1ah), AOW 0/1 (10h/1dh) */
-       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
+       set_pin_power_state(codec, 0x19, &parm);
+       if (spec->smart51_enabled)
+               set_pin_power_state(codec, 0x1b, &parm);
+       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* PW6 (22h), SW2 (26h), AOW2 (24h) */
+       if (is_8ch) {
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x22, &parm);
+               if (spec->smart51_enabled)
+                       set_pin_power_state(codec, 0x1a, &parm);
+               snd_hda_codec_write(codec, 0x26, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x24, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       } else if (codec->vendor_id == 0x11064397) {
+               /* PW7(23h), SW2(27h), AOW2(25h) */
+               parm = AC_PWRST_D3;
+               set_pin_power_state(codec, 0x23, &parm);
+               if (spec->smart51_enabled)
+                       set_pin_power_state(codec, 0x1a, &parm);
+               snd_hda_codec_write(codec, 0x27, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x25, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       }
+
+       /* PW 3/4/7 (1ch/1dh/23h) */
+       parm = AC_PWRST_D3;
+       /* force to D0 for internal Speaker */
+       set_pin_power_state(codec, 0x1c, &parm);
+       set_pin_power_state(codec, 0x1d, &parm);
+       if (is_8ch)
+               set_pin_power_state(codec, 0x23, &parm);
+
+       /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
+       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
                            imux_is_smixer ? AC_PWRST_D0 : parm);
        snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
-       snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
+       if (is_8ch) {
+               snd_hda_codec_write(codec, 0x25, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+               snd_hda_codec_write(codec, 0x27, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
+       } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode)
+               snd_hda_codec_write(codec, 0x25, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
 }
 
-static int patch_vt1702(struct hda_codec *codec)
+static int patch_vt1708S(struct hda_codec *codec);
+static int patch_vt1708B(struct hda_codec *codec)
 {
        struct via_spec *spec;
        int err;
 
+       if (get_codec_type(codec) == VT1708BCE)
+               return patch_vt1708S(codec);
+
        /* create a codec specific record */
        spec = via_new_spec(codec);
        if (spec == NULL)
                return -ENOMEM;
 
+       spec->aa_mix_nid = 0x16;
+
        /* automatic parse from the BIOS config */
-       err = vt1702_parse_auto_config(codec);
+       err = via_parse_auto_config(codec);
        if (err < 0) {
                via_free(codec);
                return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration "
-                      "from BIOS.  Using genenic mode...\n");
-       }
-
-       spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
-
-       spec->stream_name_analog = "VT1702 Analog";
-       spec->stream_analog_playback = &vt1702_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1702_pcm_analog_capture;
-
-       spec->stream_name_digital = "VT1702 Digital";
-       spec->stream_digital_playback = &vt1702_pcm_digital_playback;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1702_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
-               get_mux_nids(codec);
-               spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
-               spec->num_mixers++;
        }
 
        codec->patch_ops = via_patch_ops;
 
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1702_loopbacks;
-#endif
+       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
 
-       spec->set_widgets_power_state =  set_widgets_power_state_vt1702;
        return 0;
 }
 
-/* Patch for VT1718S */
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1718S_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
-                        HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               .name = "Input Source",
-               .count = 2,
-               .info = via_mux_enum_info,
-               .get = via_mux_enum_get,
-               .put = via_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb vt1718S_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-       /* Enable MW0 adjust Gain 5 */
-       {0x1, 0xfb2, 0x10},
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
-       /* PW9 PW10 Output enable */
-       {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
-       {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
-       /* PW11 Input enable */
-       {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN},
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xf88, 0x8},
-       /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
-       {0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
-       {0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
-       { }
-};
-
-
-static const struct hda_verb vt1718S_uniwill_init_verbs[] = {
-       {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
-       {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+/* Patch for VT1708S */
+static const struct hda_verb vt1708S_init_verbs[] = {
+       /* Enable Mic Boost Volume backdoor */
+       {0x1, 0xf98, 0x1},
+       /* don't bybass mixer */
+       {0x1, 0xf88, 0xc0},
        { }
 };
 
-static const struct hda_pcm_stream vt1718S_pcm_analog_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 10,
-       .nid = 0x8, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-               .close = via_pcm_open_close,
-       },
-};
-
-static const struct hda_pcm_stream vt1718S_pcm_analog_capture = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_pcm_open_close,
-               .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup,
-               .close = via_pcm_open_close,
-       },
-};
-
-static const struct hda_pcm_stream vt1718S_pcm_digital_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in via_build_pcms */
-       .ops = {
-               .open = via_dig_playback_pcm_open,
-               .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare,
-               .cleanup = via_dig_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream vt1718S_pcm_digital_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
-                                    const struct auto_pin_cfg *cfg)
+/* fill out digital output widgets; one for master and one for slave outputs */
+static void fill_dig_outs(struct hda_codec *codec)
 {
+       struct via_spec *spec = codec->spec;
        int i;
-       hda_nid_t nid;
-
-       spec->multiout.num_dacs = cfg->line_outs;
 
-       spec->multiout.dac_nids = spec->private_dac_nids;
+       for (i = 0; i < spec->autocfg.dig_outs; i++) {
+               hda_nid_t nid;
+               int conn;
 
-       for (i = 0; i < 4; i++) {
-               nid = cfg->line_out_pins[i];
-               if (nid) {
-                       /* config dac list */
-                       switch (i) {
-                       case AUTO_SEQ_FRONT:
-                               spec->private_dac_nids[i] = 0x8;
-                               break;
-                       case AUTO_SEQ_CENLFE:
-                               spec->private_dac_nids[i] = 0xa;
-                               break;
-                       case AUTO_SEQ_SURROUND:
-                               spec->private_dac_nids[i] = 0x9;
-                               break;
-                       case AUTO_SEQ_SIDE:
-                               spec->private_dac_nids[i] = 0xb;
-                               break;
-                       }
+               nid = spec->autocfg.dig_out_pins[i];
+               if (!nid)
+                       continue;
+               conn = snd_hda_get_connections(codec, nid, &nid, 1);
+               if (conn < 1)
+                       continue;
+               if (!spec->multiout.dig_out_nid)
+                       spec->multiout.dig_out_nid = nid;
+               else {
+                       spec->slave_dig_outs[0] = nid;
+                       break; /* at most two dig outs */
                }
        }
-
-       return 0;
 }
 
-/* add playback controls from the parsed DAC table */
-static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
+static void fill_dig_in(struct hda_codec *codec)
 {
-       char name[32];
-       static const char * const chname[4] = {
-               "Front", "Surround", "C/LFE", "Side"
-       };
-       hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
-       hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
-       hda_nid_t nid, nid_vol, nid_mute = 0;
+       struct via_spec *spec = codec->spec;
+       hda_nid_t dig_nid;
        int i, err;
 
-       for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
-               nid = cfg->line_out_pins[i];
+       if (!spec->autocfg.dig_in_pin)
+               return;
 
-               if (!nid)
+       dig_nid = codec->start_nid;
+       for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
+               unsigned int wcaps = get_wcaps(codec, dig_nid);
+               if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
                        continue;
-               nid_vol = nid_vols[i];
-               nid_mute = nid_mutes[i];
-
-               if (i == AUTO_SEQ_CENLFE) {
-                       /* Center/LFE */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Center Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "LFE Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
-                                                                 HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_MUTE,
-                               "Center Playback Switch",
-                               HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
-                                                   HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_MUTE,
-                               "LFE Playback Switch",
-                               HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
-                                                   HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else if (i == AUTO_SEQ_FRONT) {
-                       /* add control to mixer index 0 */
-                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Master Front Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x21, 3, 5,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                                             "Master Front Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x21, 3, 5,
-                                                                 HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       /* Front */
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_VOL, name,
-                               HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_MUTE, name,
-                               HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
-                                                   HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_VOL, name,
-                               HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_MUTE, name,
-                               HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
-                                                   HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
+               if (!(wcaps & AC_WCAP_DIGITAL))
+                       continue;
+               if (!(wcaps & AC_WCAP_CONN_LIST))
+                       continue;
+               err = get_connection_index(codec, dig_nid,
+                                          spec->autocfg.dig_in_pin);
+               if (err >= 0) {
+                       spec->dig_in_nid = dig_nid;
+                       break;
                }
        }
-       return 0;
 }
 
-static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
+                              int offset, int num_steps, int step_size)
+{
+       snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
+                                 (offset << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (0 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+static int patch_vt1708S(struct hda_codec *codec)
 {
+       struct via_spec *spec;
        int err;
 
-       if (!pin)
-               return 0;
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
 
-       spec->multiout.hp_nid = 0xc; /* AOW4 */
-       spec->hp_independent_mode_index = 1;
+       spec->aa_mix_nid = 0x16;
+       override_mic_boost(codec, 0x1a, 0, 3, 40);
+       override_mic_boost(codec, 0x1e, 0, 3, 40);
 
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT));
-       if (err < 0)
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
                return err;
+       }
 
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
+       spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs;
 
-       create_hp_imux(spec);
+       codec->patch_ops = via_patch_ops;
+
+       /* correct names for VT1708BCE */
+       if (get_codec_type(codec) == VT1708BCE) {
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
+               snprintf(codec->bus->card->mixername,
+                        sizeof(codec->bus->card->mixername),
+                        "%s %s", codec->vendor_name, codec->chip_name);
+       }
+       /* correct names for VT1705 */
+       if (codec->vendor_id == 0x11064397)     {
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
+               snprintf(codec->bus->card->mixername,
+                        sizeof(codec->bus->card->mixername),
+                        "%s %s", codec->vendor_name, codec->chip_name);
+       }
+       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
        return 0;
 }
 
-/* create playback/capture controls for input pins */
-static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       static const hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
-       return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
-                                               ARRAY_SIZE(pin_idxs));
+/* Patch for VT1702 */
+
+static const struct hda_verb vt1702_init_verbs[] = {
+       /* mixer enable */
+       {0x1, 0xF88, 0x3},
+       /* GPIO 0~2 */
+       {0x1, 0xF82, 0x3F},
+       { }
+};
+
+static void set_widgets_power_state_vt1702(struct hda_codec *codec)
+{
+       int imux_is_smixer =
+       snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+       unsigned int parm;
+       /* inputs */
+       /* PW 1/2/5 (14h/15h/18h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x14, &parm);
+       set_pin_power_state(codec, 0x15, &parm);
+       set_pin_power_state(codec, 0x18, &parm);
+       if (imux_is_smixer)
+               parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */
+       /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
+       snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm);
+
+       /* outputs */
+       /* PW 3/4 (16h/17h) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x17, &parm);
+       set_pin_power_state(codec, 0x16, &parm);
+       /* MW0 (1ah), AOW 0/1 (10h/1dh) */
+       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
+                           imux_is_smixer ? AC_PWRST_D0 : parm);
+       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
 }
 
-static int vt1718S_parse_auto_config(struct hda_codec *codec)
+static int patch_vt1702(struct hda_codec *codec)
 {
-       struct via_spec *spec = codec->spec;
+       struct via_spec *spec;
        int err;
 
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-
-       if (err < 0)
-               return err;
-       err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
-               return 0; /* can't find valid BIOS pin config */
-
-       err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
-       if (err < 0)
-               return err;
-       err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
 
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+       spec->aa_mix_nid = 0x1a;
 
-       fill_dig_outs(codec);
+       /* limit AA path volume to 0 dB */
+       snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
+                                 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
 
-       if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428)
-               spec->dig_in_nid = 0x13;
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       }
 
-       if (spec->kctls.list)
-               spec->mixers[spec->num_mixers++] = spec->kctls.list;
+       spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs;
 
-       spec->input_mux = &spec->private_imux[0];
+       codec->patch_ops = via_patch_ops;
 
-       if (spec->hp_mux)
-               via_hp_build(codec);
+       spec->set_widgets_power_state =  set_widgets_power_state_vt1702;
+       return 0;
+}
 
-       via_smart51_build(spec);
+/* Patch for VT1718S */
 
-       return 1;
-}
+static const struct hda_verb vt1718S_init_verbs[] = {
+       /* Enable MW0 adjust Gain 5 */
+       {0x1, 0xfb2, 0x10},
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xf88, 0x8},
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1718S_loopbacks[] = {
-       { 0x21, HDA_INPUT, 1 },
-       { 0x21, HDA_INPUT, 2 },
-       { 0x21, HDA_INPUT, 3 },
-       { 0x21, HDA_INPUT, 4 },
-       { } /* end */
+       { }
 };
-#endif
 
 static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
 {
@@ -4664,6 +3244,41 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
        }
 }
 
+/* Add a connection to the primary DAC from AA-mixer for some codecs
+ * This isn't listed from the raw info, but the chip has a secret connection.
+ */
+static int add_secret_dac_path(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int i, nums;
+       hda_nid_t conn[8];
+       hda_nid_t nid;
+
+       if (!spec->aa_mix_nid)
+               return 0;
+       nums = snd_hda_get_connections(codec, spec->aa_mix_nid, conn,
+                                      ARRAY_SIZE(conn) - 1);
+       for (i = 0; i < nums; i++) {
+               if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT)
+                       return 0;
+       }
+
+       /* find the primary DAC and add to the connection list */
+       nid = codec->start_nid;
+       for (i = 0; i < codec->num_nodes; i++, nid++) {
+               unsigned int caps = get_wcaps(codec, nid);
+               if (get_wcaps_type(caps) == AC_WID_AUD_OUT &&
+                   !(caps & AC_WCAP_DIGITAL)) {
+                       conn[nums++] = nid;
+                       return snd_hda_override_conn_list(codec,
+                                                         spec->aa_mix_nid,
+                                                         nums, conn);
+               }
+       }
+       return 0;
+}
+
+
 static int patch_vt1718S(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -4674,57 +3289,22 @@ static int patch_vt1718S(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
 
+       spec->aa_mix_nid = 0x21;
+       override_mic_boost(codec, 0x2b, 0, 3, 40);
+       override_mic_boost(codec, 0x29, 0, 3, 40);
+       add_secret_dac_path(codec);
+
        /* automatic parse from the BIOS config */
-       err = vt1718S_parse_auto_config(codec);
+       err = via_parse_auto_config(codec);
        if (err < 0) {
                via_free(codec);
                return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration "
-                      "from BIOS.  Using genenic mode...\n");
        }
 
-       spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs;
-
-       if (codec->vendor_id == 0x11060441)
-               spec->stream_name_analog = "VT2020 Analog";
-       else if (codec->vendor_id == 0x11064441)
-               spec->stream_name_analog = "VT1828S Analog";
-       else
-               spec->stream_name_analog = "VT1718S Analog";
-       spec->stream_analog_playback = &vt1718S_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1718S_pcm_analog_capture;
-
-       if (codec->vendor_id == 0x11060441)
-               spec->stream_name_digital = "VT2020 Digital";
-       else if (codec->vendor_id == 0x11064441)
-               spec->stream_name_digital = "VT1828S Digital";
-       else
-               spec->stream_name_digital = "VT1718S Digital";
-       spec->stream_digital_playback = &vt1718S_pcm_digital_playback;
-       if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441)
-               spec->stream_digital_capture = &vt1718S_pcm_digital_capture;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1718S_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids);
-               get_mux_nids(codec);
-               override_mic_boost(codec, 0x2b, 0, 3, 40);
-               override_mic_boost(codec, 0x29, 0, 3, 40);
-               spec->mixers[spec->num_mixers] = vt1718S_capture_mixer;
-               spec->num_mixers++;
-       }
+       spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs;
 
        codec->patch_ops = via_patch_ops;
 
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1718S_loopbacks;
-#endif
-
        spec->set_widgets_power_state =  set_widgets_power_state_vt1718S;
 
        return 0;
@@ -4748,382 +3328,58 @@ static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        int index = 0;
 
-       index = snd_hda_codec_read(codec, 0x26, 0,
-                                              AC_VERB_GET_CONNECT_SEL, 0);
-       if (index != -1)
-               *ucontrol->value.integer.value = index;
-
-       return 0;
-}
-
-static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-       int index = *ucontrol->value.integer.value;
-
-       snd_hda_codec_write(codec, 0x26, 0,
-                                              AC_VERB_SET_CONNECT_SEL, index);
-       spec->dmic_enabled = index;
-       set_widgets_power_state(codec);
-       return 1;
-}
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1716S_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
-                        HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Input Source",
-               .count = 1,
-               .info = via_mux_enum_info,
-               .get = via_mux_enum_get,
-               .put = via_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
-       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
-       {
-        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name = "Digital Mic Capture Switch",
-        .subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
-        .count = 1,
-        .info = vt1716s_dmic_info,
-        .get = vt1716s_dmic_get,
-        .put = vt1716s_dmic_put,
-        },
-       {}                      /* end */
-};
-
-
-/* mono-out mixer elements */
-static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
-       HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct hda_verb vt1716S_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /* MUX Indices: Stereo Mixer = 5 */
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x5},
-
-       /* Setup default input of PW4 to MW0 */
-       {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
-
-       /* Setup default input of SW1 as MW0 */
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x1},
-
-       /* Setup default input of SW4 as AOW0 */
-       {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
-
-       /* PW9 PW10 Output enable */
-       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-
-       /* Unmute SW1, PW12 */
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* PW12 Output enable */
-       {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xf8a, 0x80},
-       /* don't bybass mixer */
-       {0x1, 0xf88, 0xc0},
-       /* Enable mono output */
-       {0x1, 0xf90, 0x08},
-       { }
-};
-
-
-static const struct hda_verb vt1716S_uniwill_init_verbs[] = {
-       {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
-       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT},
-       {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       { }
-};
-
-static const struct hda_pcm_stream vt1716S_pcm_analog_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 6,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-               .close = via_pcm_open_close,
-       },
-};
-
-static const struct hda_pcm_stream vt1716S_pcm_analog_capture = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x13, /* NID to query formats and rates */
-       .ops = {
-               .open = via_pcm_open_close,
-               .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup,
-               .close = via_pcm_open_close,
-       },
-};
-
-static const struct hda_pcm_stream vt1716S_pcm_digital_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in via_build_pcms */
-       .ops = {
-               .open = via_dig_playback_pcm_open,
-               .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare,
-               .cleanup = via_dig_playback_pcm_cleanup
-       },
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
-                                     const struct auto_pin_cfg *cfg)
-{      int i;
-       hda_nid_t nid;
-
-       spec->multiout.num_dacs = cfg->line_outs;
-
-       spec->multiout.dac_nids = spec->private_dac_nids;
-
-       for (i = 0; i < 3; i++) {
-               nid = cfg->line_out_pins[i];
-               if (nid) {
-                       /* config dac list */
-                       switch (i) {
-                       case AUTO_SEQ_FRONT:
-                               spec->private_dac_nids[i] = 0x10;
-                               break;
-                       case AUTO_SEQ_CENLFE:
-                               spec->private_dac_nids[i] = 0x25;
-                               break;
-                       case AUTO_SEQ_SURROUND:
-                               spec->private_dac_nids[i] = 0x11;
-                               break;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
-                                             const struct auto_pin_cfg *cfg)
-{
-       char name[32];
-       static const char * const chname[3] = {
-               "Front", "Surround", "C/LFE"
-       };
-       hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
-       hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
-       hda_nid_t nid, nid_vol, nid_mute;
-       int i, err;
-
-       for (i = 0; i <= AUTO_SEQ_CENLFE; i++) {
-               nid = cfg->line_out_pins[i];
-
-               if (!nid)
-                       continue;
-
-               nid_vol = nid_vols[i];
-               nid_mute = nid_mutes[i];
-
-               if (i == AUTO_SEQ_CENLFE) {
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_VOL,
-                               "Center Playback Volume",
-                               HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_VOL,
-                               "LFE Playback Volume",
-                               HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_MUTE,
-                               "Center Playback Switch",
-                               HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
-                                                   HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_MUTE,
-                               "LFE Playback Switch",
-                               HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
-                                                   HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else if (i == AUTO_SEQ_FRONT) {
-
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_VOL,
-                               "Master Front Playback Volume",
-                               HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_MUTE,
-                               "Master Front Playback Switch",
-                               HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
-                       if (err < 0)
-                               return err;
-
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_VOL, name,
-                               HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_MUTE, name,
-                               HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
-                                                   HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_VOL, name,
-                               HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = via_add_control(
-                               spec, VIA_CTL_WIDGET_MUTE, name,
-                               HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
-                                                   HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
-       int err;
-
-       if (!pin)
-               return 0;
-
-       spec->multiout.hp_nid = 0x25; /* AOW3 */
-       spec->hp_independent_mode_index = 1;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
+       index = snd_hda_codec_read(codec, 0x26, 0,
+                                              AC_VERB_GET_CONNECT_SEL, 0);
+       if (index != -1)
+               *ucontrol->value.integer.value = index;
 
-       create_hp_imux(spec);
        return 0;
 }
 
-/* create playback/capture controls for input pins */
-static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
-       return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
-                                               ARRAY_SIZE(pin_idxs));
-}
-
-static int vt1716S_parse_auto_config(struct hda_codec *codec)
+static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
 {
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       int err;
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-       if (err < 0)
-               return err;
-       err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
-               return 0; /* can't find valid BIOS pin config */
-
-       err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
-       if (err < 0)
-               return err;
-       err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       fill_dig_outs(codec);
-
-       if (spec->kctls.list)
-               spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
-       spec->input_mux = &spec->private_imux[0];
-
-       if (spec->hp_mux)
-               via_hp_build(codec);
-
-       via_smart51_build(spec);
+       int index = *ucontrol->value.integer.value;
 
+       snd_hda_codec_write(codec, 0x26, 0,
+                                              AC_VERB_SET_CONNECT_SEL, index);
+       spec->dmic_enabled = index;
+       set_widgets_power_state(codec);
        return 1;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1716S_loopbacks[] = {
-       { 0x16, HDA_INPUT, 1 },
-       { 0x16, HDA_INPUT, 2 },
-       { 0x16, HDA_INPUT, 3 },
-       { 0x16, HDA_INPUT, 4 },
+static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
+       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
+       {
+        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name = "Digital Mic Capture Switch",
+        .subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
+        .count = 1,
+        .info = vt1716s_dmic_info,
+        .get = vt1716s_dmic_get,
+        .put = vt1716s_dmic_put,
+        },
+       {}                      /* end */
+};
+
+
+/* mono-out mixer elements */
+static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
+       HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
        { } /* end */
 };
-#endif
+
+static const struct hda_verb vt1716S_init_verbs[] = {
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xf8a, 0x80},
+       /* don't bybass mixer */
+       {0x1, 0xf88, 0xc0},
+       /* Enable mono output */
+       {0x1, 0xf90, 0x08},
+       { }
+};
 
 static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
 {
@@ -5176,442 +3432,103 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
        /* Smart 5.1 PW1(1ah) */
        if (spec->smart51_enabled)
                set_pin_power_state(codec, 0x1a, &parm);
-       snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm);
-
-       /* Smart 5.1 PW5(1eh) */
-       if (spec->smart51_enabled)
-               set_pin_power_state(codec, 0x1e, &parm);
-       snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm);
-
-       /* Mono out */
-       /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
-       present = snd_hda_jack_detect(codec, 0x1c);
-
-       if (present)
-               mono_out = 0;
-       else {
-               present = snd_hda_jack_detect(codec, 0x1d);
-               if (!spec->hp_independent_mode && present)
-                       mono_out = 0;
-               else
-                       mono_out = 1;
-       }
-       parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
-       snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm);
-       snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm);
-       snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm);
-
-       /* PW 3/4 (1ch/1dh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x1c, &parm);
-       set_pin_power_state(codec, 0x1d, &parm);
-       /* HP Independent Mode, power on AOW3 */
-       if (spec->hp_independent_mode)
-               snd_hda_codec_write(codec, 0x25, 0,
-                                   AC_VERB_SET_POWER_STATE, parm);
-
-       /* force to D0 for internal Speaker */
-       /* MW0 (16h), AOW0 (10h) */
-       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
-                           imux_is_smixer ? AC_PWRST_D0 : parm);
-       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-                           mono_out ? AC_PWRST_D0 : parm);
-}
-
-static int patch_vt1716S(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       /* automatic parse from the BIOS config */
-       err = vt1716S_parse_auto_config(codec);
-       if (err < 0) {
-               via_free(codec);
-               return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration "
-                      "from BIOS.  Using genenic mode...\n");
-       }
-
-       spec->init_verbs[spec->num_iverbs++]  = vt1716S_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs;
-
-       spec->stream_name_analog = "VT1716S Analog";
-       spec->stream_analog_playback = &vt1716S_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1716S_pcm_analog_capture;
-
-       spec->stream_name_digital = "VT1716S Digital";
-       spec->stream_digital_playback = &vt1716S_pcm_digital_playback;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1716S_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids);
-               get_mux_nids(codec);
-               override_mic_boost(codec, 0x1a, 0, 3, 40);
-               override_mic_boost(codec, 0x1e, 0, 3, 40);
-               spec->mixers[spec->num_mixers] = vt1716S_capture_mixer;
-               spec->num_mixers++;
-       }
-
-       spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
-       spec->num_mixers++;
-
-       spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
-
-       codec->patch_ops = via_patch_ops;
-
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1716S_loopbacks;
-#endif
-
-       spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
-       return 0;
-}
-
-/* for vt2002P */
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt2002P_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
-                        HDA_INPUT),
-       {
-               .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 = via_mux_enum_info,
-               .get = via_mux_enum_get,
-               .put = via_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb vt2002P_volume_init_verbs[] = {
-       /* Class-D speaker related verbs */
-       {0x1, 0xfe0, 0x4},
-       {0x1, 0xfe9, 0x80},
-       {0x1, 0xfe2, 0x22},
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /* MUX Indices: Mic = 0 */
-       {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* PW9 Output enable */
-       {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
-
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xfb9, 0x24},
-
-       /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* set MUX0/1/4/8 = 0 (AOW0) */
-       {0x34, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x35, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x3b, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* set PW0 index=0 (MW0) */
-       {0x24, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* Enable AOW0 to MW9 */
-       {0x1, 0xfb8, 0x88},
-       { }
-};
-static const struct hda_verb vt1802_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /* MUX Indices: Mic = 0 */
-       {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* PW9 Output enable */
-       {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
-
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xfb9, 0x24},
-
-       /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* set MUX0/1/4/8 = 0 (AOW0) */
-       {0x34, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x35, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x38, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* set PW0 index=0 (MW0) */
-       {0x24, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* Enable AOW0 to MW9 */
-       {0x1, 0xfb8, 0x88},
-       { }
-};
-
-
-static const struct hda_verb vt2002P_uniwill_init_verbs[] = {
-       {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
-       {0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
-       {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       { }
-};
-static const struct hda_verb vt1802_uniwill_init_verbs[] = {
-       {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
-       {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
-       {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       { }
-};
-
-static const struct hda_pcm_stream vt2002P_pcm_analog_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x8, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-               .close = via_pcm_open_close,
-       },
-};
-
-static const struct hda_pcm_stream vt2002P_pcm_analog_capture = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_pcm_open_close,
-               .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup,
-               .close = via_pcm_open_close,
-       },
-};
-
-static const struct hda_pcm_stream vt2002P_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in via_build_pcms */
-       .ops = {
-               .open = via_dig_playback_pcm_open,
-               .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare,
-               .cleanup = via_dig_playback_pcm_cleanup
-       },
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
-                                     const struct auto_pin_cfg *cfg)
-{
-       spec->multiout.num_dacs = 1;
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       if (cfg->line_out_pins[0])
-               spec->private_dac_nids[0] = 0x8;
-       return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       int err;
-       hda_nid_t sw_nid;
-
-       if (!cfg->line_out_pins[0])
-               return -1;
-
-       if (spec->codec_type == VT1802)
-               sw_nid = 0x28;
-       else
-               sw_nid = 0x26;
-
-       /* Line-Out: PortE */
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Master Front Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-       err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
-                             "Master Front Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
-       int err;
-
-       if (!pin)
-               return 0;
-
-       spec->multiout.hp_nid = 0x9;
-       spec->hp_independent_mode_index = 1;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(
-                                     spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
+       snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm);
 
-       create_hp_imux(spec);
-       return 0;
-}
+       /* Smart 5.1 PW5(1eh) */
+       if (spec->smart51_enabled)
+               set_pin_power_state(codec, 0x1e, &parm);
+       snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm);
 
-/* create playback/capture controls for input pins */
-static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       struct via_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
-       int err;
+       /* Mono out */
+       /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
+       present = snd_hda_jack_detect(codec, 0x1c);
 
-       err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
-                                              ARRAY_SIZE(pin_idxs));
-       if (err < 0)
-               return err;
-       /* build volume/mute control of loopback */
-       err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21);
-       if (err < 0)
-               return err;
+       if (present)
+               mono_out = 0;
+       else {
+               present = snd_hda_jack_detect(codec, 0x1d);
+               if (!spec->hp_independent_mode && present)
+                       mono_out = 0;
+               else
+                       mono_out = 1;
+       }
+       parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
+       snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm);
+       snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm);
 
-       /* for digital mic select */
-       snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL);
+       /* PW 3/4 (1ch/1dh) */
+       parm = AC_PWRST_D3;
+       set_pin_power_state(codec, 0x1c, &parm);
+       set_pin_power_state(codec, 0x1d, &parm);
+       /* HP Independent Mode, power on AOW3 */
+       if (spec->hp_independent_mode)
+               snd_hda_codec_write(codec, 0x25, 0,
+                                   AC_VERB_SET_POWER_STATE, parm);
 
-       return 0;
+       /* force to D0 for internal Speaker */
+       /* MW0 (16h), AOW0 (10h) */
+       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+                           imux_is_smixer ? AC_PWRST_D0 : parm);
+       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+                           mono_out ? AC_PWRST_D0 : parm);
 }
 
-static int vt2002P_parse_auto_config(struct hda_codec *codec)
+static int patch_vt1716S(struct hda_codec *codec)
 {
-       struct via_spec *spec = codec->spec;
+       struct via_spec *spec;
        int err;
 
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
 
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-       if (err < 0)
-               return err;
+       spec->aa_mix_nid = 0x16;
+       override_mic_boost(codec, 0x1a, 0, 3, 40);
+       override_mic_boost(codec, 0x1e, 0, 3, 40);
 
-       err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
                return err;
+       }
 
-       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
-               return 0; /* can't find valid BIOS pin config */
-
-       err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
-       if (err < 0)
-               return err;
-       err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
+       spec->init_verbs[spec->num_iverbs++]  = vt1716S_init_verbs;
 
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+       spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
+       spec->num_mixers++;
 
-       fill_dig_outs(codec);
+       spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
 
-       if (spec->kctls.list)
-               spec->mixers[spec->num_mixers++] = spec->kctls.list;
+       codec->patch_ops = via_patch_ops;
 
-       spec->input_mux = &spec->private_imux[0];
+       spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
+       return 0;
+}
 
-       if (spec->hp_mux)
-               via_hp_build(codec);
+/* for vt2002P */
 
-       return 1;
-}
+static const struct hda_verb vt2002P_init_verbs[] = {
+       /* Class-D speaker related verbs */
+       {0x1, 0xfe0, 0x4},
+       {0x1, 0xfe9, 0x80},
+       {0x1, 0xfe2, 0x22},
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xfb9, 0x24},
+       /* Enable AOW0 to MW9 */
+       {0x1, 0xfb8, 0x88},
+       { }
+};
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt2002P_loopbacks[] = {
-       { 0x21, HDA_INPUT, 0 },
-       { 0x21, HDA_INPUT, 1 },
-       { 0x21, HDA_INPUT, 2 },
-       { } /* end */
+static const struct hda_verb vt1802_init_verbs[] = {
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xfb9, 0x24},
+       /* Enable AOW0 to MW9 */
+       {0x1, 0xfb8, 0x88},
+       { }
 };
-#endif
 
 static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
 {
@@ -5735,334 +3652,39 @@ static int patch_vt2002P(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
 
+       spec->aa_mix_nid = 0x21;
+       override_mic_boost(codec, 0x2b, 0, 3, 40);
+       override_mic_boost(codec, 0x29, 0, 3, 40);
+       add_secret_dac_path(codec);
+
        /* automatic parse from the BIOS config */
-       err = vt2002P_parse_auto_config(codec);
+       err = via_parse_auto_config(codec);
        if (err < 0) {
                via_free(codec);
                return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration "
-                      "from BIOS.  Using genenic mode...\n");
        }
 
        if (spec->codec_type == VT1802)
-               spec->init_verbs[spec->num_iverbs++]  =
-                       vt1802_volume_init_verbs;
-       else
-               spec->init_verbs[spec->num_iverbs++]  =
-                       vt2002P_volume_init_verbs;
-
-       if (spec->codec_type == VT1802)
-               spec->init_verbs[spec->num_iverbs++] =
-                       vt1802_uniwill_init_verbs;
+               spec->init_verbs[spec->num_iverbs++] = vt1802_init_verbs;
        else
-               spec->init_verbs[spec->num_iverbs++] =
-                       vt2002P_uniwill_init_verbs;
-
-       if (spec->codec_type == VT1802)
-               spec->stream_name_analog = "VT1802 Analog";
-       else
-               spec->stream_name_analog = "VT2002P Analog";
-       spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
-       spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
-
-       if (spec->codec_type == VT1802)
-               spec->stream_name_digital = "VT1802 Digital";
-       else
-               spec->stream_name_digital = "VT2002P Digital";
-       spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt2002P_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids);
-               get_mux_nids(codec);
-               override_mic_boost(codec, 0x2b, 0, 3, 40);
-               override_mic_boost(codec, 0x29, 0, 3, 40);
-               spec->mixers[spec->num_mixers] = vt2002P_capture_mixer;
-               spec->num_mixers++;
-       }
+               spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs;
 
        codec->patch_ops = via_patch_ops;
 
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt2002P_loopbacks;
-#endif
-
        spec->set_widgets_power_state =  set_widgets_power_state_vt2002P;
        return 0;
 }
 
 /* for vt1812 */
 
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1812_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0,
-                      HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               .name = "Input Source",
-               .count = 2,
-               .info = via_mux_enum_info,
-               .get = via_mux_enum_get,
-               .put = via_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb vt1812_volume_init_verbs[] = {
-       /*
-        * Unmute ADC0-1 and set the default input to mic-in
-        */
-       {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        */
-       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
-       /* MUX Indices: Mic = 0 */
-       {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
-
-       /* PW9 Output enable */
-       {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
-
+static const struct hda_verb vt1812_init_verbs[] = {
        /* Enable Boost Volume backdoor */
        {0x1, 0xfb9, 0x24},
-
-       /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* set MUX0/1/4/13/15 = 0 (AOW0) */
-       {0x34, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x35, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x38, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
-       {0x3d, AC_VERB_SET_CONNECT_SEL, 0},
-
        /* Enable AOW0 to MW9 */
        {0x1, 0xfb8, 0xa8},
        { }
 };
 
-
-static const struct hda_verb vt1812_uniwill_init_verbs[] = {
-       {0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
-       {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
-       {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
-        AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
-       {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
-       { }
-};
-
-static const struct hda_pcm_stream vt1812_pcm_analog_playback = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x8, /* NID to query formats and rates */
-       .ops = {
-               .open = via_playback_pcm_open,
-               .prepare = via_playback_multi_pcm_prepare,
-               .cleanup = via_playback_multi_pcm_cleanup,
-               .close = via_pcm_open_close,
-       },
-};
-
-static const struct hda_pcm_stream vt1812_pcm_analog_capture = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x10, /* NID to query formats and rates */
-       .ops = {
-               .open = via_pcm_open_close,
-               .prepare = via_capture_pcm_prepare,
-               .cleanup = via_capture_pcm_cleanup,
-               .close = via_pcm_open_close,
-       },
-};
-
-static const struct hda_pcm_stream vt1812_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in via_build_pcms */
-       .ops = {
-               .open = via_dig_playback_pcm_open,
-               .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare,
-               .cleanup = via_dig_playback_pcm_cleanup
-       },
-};
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1812_auto_fill_dac_nids(struct via_spec *spec,
-                                    const struct auto_pin_cfg *cfg)
-{
-       spec->multiout.num_dacs = 1;
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       if (cfg->line_out_pins[0])
-               spec->private_dac_nids[0] = 0x8;
-       return 0;
-}
-
-
-/* add playback controls from the parsed DAC table */
-static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       int err;
-
-       if (!cfg->line_out_pins[0])
-               return -1;
-
-       /* Line-Out: PortE */
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Front Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-       err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
-                             "Front Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
-       int err;
-
-       if (!pin)
-               return 0;
-
-       spec->multiout.hp_nid = 0x9;
-       spec->hp_independent_mode_index = 1;
-
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                             "Headphone Playback Volume",
-                             HDA_COMPOSE_AMP_VAL(
-                                     spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-
-       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
-                             "Headphone Playback Switch",
-                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-
-       create_hp_imux(spec);
-       return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       struct via_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
-       int err;
-
-       err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
-                                              ARRAY_SIZE(pin_idxs));
-       if (err < 0)
-               return err;
-
-       /* build volume/mute control of loopback */
-       err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21);
-       if (err < 0)
-               return err;
-
-       /* for digital mic select */
-       snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL);
-
-       return 0;
-}
-
-static int vt1812_parse_auto_config(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int err;
-
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-       if (err < 0)
-               return err;
-       fill_dig_outs(codec);
-       err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs)
-               return 0; /* can't find valid BIOS pin config */
-
-       err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
-       if (err < 0)
-               return err;
-       err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       fill_dig_outs(codec);
-
-       if (spec->kctls.list)
-               spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
-       spec->input_mux = &spec->private_imux[0];
-
-       if (spec->hp_mux)
-               via_hp_build(codec);
-
-       return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1812_loopbacks[] = {
-       { 0x21, HDA_INPUT, 0 },
-       { 0x21, HDA_INPUT, 1 },
-       { 0x21, HDA_INPUT, 2 },
-       { } /* end */
-};
-#endif
-
 static void set_widgets_power_state_vt1812(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
@@ -6166,47 +3788,22 @@ static int patch_vt1812(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
 
+       spec->aa_mix_nid = 0x21;
+       override_mic_boost(codec, 0x2b, 0, 3, 40);
+       override_mic_boost(codec, 0x29, 0, 3, 40);
+       add_secret_dac_path(codec);
+
        /* automatic parse from the BIOS config */
-       err = vt1812_parse_auto_config(codec);
+       err = via_parse_auto_config(codec);
        if (err < 0) {
                via_free(codec);
                return err;
-       } else if (!err) {
-               printk(KERN_INFO "hda_codec: Cannot set up configuration "
-                      "from BIOS.  Using genenic mode...\n");
        }
 
-
-       spec->init_verbs[spec->num_iverbs++]  = vt1812_volume_init_verbs;
-       spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs;
-
-       spec->stream_name_analog = "VT1812 Analog";
-       spec->stream_analog_playback = &vt1812_pcm_analog_playback;
-       spec->stream_analog_capture = &vt1812_pcm_analog_capture;
-
-       spec->stream_name_digital = "VT1812 Digital";
-       spec->stream_digital_playback = &vt1812_pcm_digital_playback;
-
-
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = vt1812_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids);
-               get_mux_nids(codec);
-               override_mic_boost(codec, 0x2b, 0, 3, 40);
-               override_mic_boost(codec, 0x29, 0, 3, 40);
-               spec->mixers[spec->num_mixers] = vt1812_capture_mixer;
-               spec->num_mixers++;
-       }
+       spec->init_verbs[spec->num_iverbs++]  = vt1812_init_verbs;
 
        codec->patch_ops = via_patch_ops;
 
-       codec->patch_ops.init = via_auto_init;
-       codec->patch_ops.unsol_event = via_unsol_event;
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       spec->loopback.amplist = vt1812_loopbacks;
-#endif
-
        spec->set_widgets_power_state =  set_widgets_power_state_vt1812;
        return 0;
 }
@@ -6220,37 +3817,37 @@ static const struct hda_codec_preset snd_hda_preset_via[] = {
        { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
        { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
        { .id = 0x1106e710, .name = "VT1709 10-Ch",
-         .patch = patch_vt1709_10ch},
+         .patch = patch_vt1709},
        { .id = 0x1106e711, .name = "VT1709 10-Ch",
-         .patch = patch_vt1709_10ch},
+         .patch = patch_vt1709},
        { .id = 0x1106e712, .name = "VT1709 10-Ch",
-         .patch = patch_vt1709_10ch},
+         .patch = patch_vt1709},
        { .id = 0x1106e713, .name = "VT1709 10-Ch",
-         .patch = patch_vt1709_10ch},
+         .patch = patch_vt1709},
        { .id = 0x1106e714, .name = "VT1709 6-Ch",
-         .patch = patch_vt1709_6ch},
+         .patch = patch_vt1709},
        { .id = 0x1106e715, .name = "VT1709 6-Ch",
-         .patch = patch_vt1709_6ch},
+         .patch = patch_vt1709},
        { .id = 0x1106e716, .name = "VT1709 6-Ch",
-         .patch = patch_vt1709_6ch},
+         .patch = patch_vt1709},
        { .id = 0x1106e717, .name = "VT1709 6-Ch",
-         .patch = patch_vt1709_6ch},
+         .patch = patch_vt1709},
        { .id = 0x1106e720, .name = "VT1708B 8-Ch",
-         .patch = patch_vt1708B_8ch},
+         .patch = patch_vt1708B},
        { .id = 0x1106e721, .name = "VT1708B 8-Ch",
-         .patch = patch_vt1708B_8ch},
+         .patch = patch_vt1708B},
        { .id = 0x1106e722, .name = "VT1708B 8-Ch",
-         .patch = patch_vt1708B_8ch},
+         .patch = patch_vt1708B},
        { .id = 0x1106e723, .name = "VT1708B 8-Ch",
-         .patch = patch_vt1708B_8ch},
+         .patch = patch_vt1708B},
        { .id = 0x1106e724, .name = "VT1708B 4-Ch",
-         .patch = patch_vt1708B_4ch},
+         .patch = patch_vt1708B},
        { .id = 0x1106e725, .name = "VT1708B 4-Ch",
-         .patch = patch_vt1708B_4ch},
+         .patch = patch_vt1708B},
        { .id = 0x1106e726, .name = "VT1708B 4-Ch",
-         .patch = patch_vt1708B_4ch},
+         .patch = patch_vt1708B},
        { .id = 0x1106e727, .name = "VT1708B 4-Ch",
-         .patch = patch_vt1708B_4ch},
+         .patch = patch_vt1708B},
        { .id = 0x11060397, .name = "VT1708S",
          .patch = patch_vt1708S},
        { .id = 0x11061397, .name = "VT1708S",
index f4594d7..be06fb3 100644 (file)
@@ -2607,7 +2607,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
        ice->profi_port = pci_resource_start(pci, 3);
 
        if (request_irq(pci->irq, snd_ice1712_interrupt, IRQF_SHARED,
-                       "ICE1712", ice)) {
+                       KBUILD_MODNAME, ice)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_ice1712_free(ice);
                return -EIO;
@@ -2802,7 +2802,7 @@ static void __devexit snd_ice1712_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "ICE1712",
+       .name = KBUILD_MODNAME,
        .id_table = snd_ice1712_ids,
        .probe = snd_ice1712_probe,
        .remove = __devexit_p(snd_ice1712_remove),
index c1498fa..c2b7f8b 100644 (file)
@@ -2509,7 +2509,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
        ice->profi_port = pci_resource_start(pci, 1);
 
        if (request_irq(pci->irq, snd_vt1724_interrupt,
-                       IRQF_SHARED, "ICE1724", ice)) {
+                       IRQF_SHARED, KBUILD_MODNAME, ice)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_vt1724_free(ice);
                return -EIO;
@@ -2802,7 +2802,7 @@ static int snd_vt1724_resume(struct pci_dev *pci)
 #endif
 
 static struct pci_driver driver = {
-       .name = "ICE1724",
+       .name = KBUILD_MODNAME,
        .id_table = snd_vt1724_ids,
        .probe = snd_vt1724_probe,
        .remove = __devexit_p(snd_vt1724_remove),
index 6c896db..6a5b387 100644 (file)
@@ -1882,6 +1882,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .name = "Dell Inspiron 6000",
                .type = AC97_TUNE_HP_MUTE_LED /* cf. Malone #41015 */
        },
+       {
+               .subvendor = 0x1028,
+               .subdevice = 0x0189,
+               .name = "Dell Inspiron 9300",
+               .type = AC97_TUNE_HP_MUTE_LED
+       },
        {
                .subvendor = 0x1028,
                .subdevice = 0x0191,
@@ -2647,7 +2653,7 @@ static int intel8x0_resume(struct pci_dev *pci)
        pci_set_master(pci);
        snd_intel8x0_chip_init(chip, 0);
        if (request_irq(pci->irq, snd_intel8x0_interrupt,
-                       IRQF_SHARED, card->shortname, chip)) {
+                       IRQF_SHARED, KBUILD_MODNAME, chip)) {
                printk(KERN_ERR "intel8x0: unable to grab IRQ %d, "
                       "disabling device\n", pci->irq);
                snd_card_disconnect(card);
@@ -3106,7 +3112,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
 
        /* request irq after initializaing int_sta_mask, etc */
        if (request_irq(pci->irq, snd_intel8x0_interrupt,
-                       IRQF_SHARED, card->shortname, chip)) {
+                       IRQF_SHARED, KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_intel8x0_free(chip);
                return -EBUSY;
@@ -3266,7 +3272,7 @@ static void __devexit snd_intel8x0_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "Intel ICH",
+       .name = KBUILD_MODNAME,
        .id_table = snd_intel8x0_ids,
        .probe = snd_intel8x0_probe,
        .remove = __devexit_p(snd_intel8x0_remove),
index f3353b4..7c16164 100644 (file)
@@ -1047,7 +1047,7 @@ static int intel8x0m_resume(struct pci_dev *pci)
        }
        pci_set_master(pci);
        if (request_irq(pci->irq, snd_intel8x0m_interrupt,
-                       IRQF_SHARED, card->shortname, chip)) {
+                       IRQF_SHARED, KBUILD_MODNAME, chip)) {
                printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, "
                       "disabling device\n", pci->irq);
                snd_card_disconnect(card);
@@ -1174,7 +1174,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
 
  port_inited:
        if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
-                       card->shortname, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_intel8x0m_free(chip);
                return -EBUSY;
@@ -1325,7 +1325,7 @@ static void __devexit snd_intel8x0m_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "Intel ICH Modem",
+       .name = KBUILD_MODNAME,
        .id_table = snd_intel8x0m_ids,
        .probe = snd_intel8x0m_probe,
        .remove = __devexit_p(snd_intel8x0m_remove),
index 6d79570..fc1d573 100644 (file)
@@ -2241,7 +2241,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
 
         err = request_irq(pci->irq, snd_korg1212_interrupt,
                           IRQF_SHARED,
-                          "korg1212", korg1212);
+                          KBUILD_MODNAME, korg1212);
 
         if (err) {
                snd_printk(KERN_ERR "korg1212: unable to grab IRQ %d\n", pci->irq);
@@ -2477,7 +2477,7 @@ static void __devexit snd_korg1212_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "korg1212",
+       .name = KBUILD_MODNAME,
        .id_table = snd_korg1212_ids,
        .probe = snd_korg1212_probe,
        .remove = __devexit_p(snd_korg1212_remove),
index 2692e5a..3e92e5b 100644 (file)
@@ -648,7 +648,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci,
                goto errout;
 
        if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED,
-                       DRVNAME, chip)) {
+                       KBUILD_MODNAME, chip)) {
                printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
                err = -EBUSY;
                goto errout;
@@ -771,7 +771,7 @@ MODULE_DEVICE_TABLE(pci, lola_ids);
 
 /* pci_driver definition */
 static struct pci_driver driver = {
-       .name = DRVNAME,
+       .name = KBUILD_MODNAME,
        .id_table = lola_ids,
        .probe = lola_probe,
        .remove = __devexit_p(lola_remove),
index d5708e2..f0b1000 100644 (file)
@@ -480,7 +480,7 @@ struct lola {
 
 /* count values in the Vendor Specific Mixer Widget's Audio Widget Capabilities */
 #define LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(res)   ((res >> 2) & 0x1f)
-#define LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(res)  ((res >> 7) & 0x1f)
+#define LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(res)  ((res >> 7) & 0x1f)
 
 int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb,
                     unsigned int data, unsigned int extdata);
index 5d518f1..6b8d648 100644 (file)
@@ -144,40 +144,61 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid)
        chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams;
        chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins;
 
-       /* mixer matrix can have unused areas between PhysIn and
+       /* mixer matrix may have unused areas between PhysIn and
         * Play or Record and PhysOut zones
         */
        chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins +
                LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val);
        chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins +
-               LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(val);
-
-       /* example : MixerMatrix of LoLa881
-        * 0-------8------16-------8------16
-        * |       |       |       |       |
-        * | INPUT |       | INPUT |       |
-        * | ->    |unused | ->    |unused |
-        * | RECORD|       | OUTPUT|       |
-        * |       |       |       |       |
-        * 8--------------------------------
-        * |       |       |       |       |
-        * |       |       |       |       |
-        * |unused |unused |unused |unused |
-        * |       |       |       |       |
-        * |       |       |       |       |
-        * 16-------------------------------
-        * |       |       |       |       |
-        * | PLAY  |       | PLAY  |       |
-        * |  ->   |unused | ->    |unused |
-        * | RECORD|       | OUTPUT|       |
-        * |       |       |       |       |
-        * 8--------------------------------
-        * |       |       |       |       |
-        * |       |       |       |       |
-        * |unused |unused |unused |unused |
-        * |       |       |       |       |
-        * |       |       |       |       |
-        * 16-------------------------------
+               LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(val);
+
+       /* example : MixerMatrix of LoLa881 (LoLa16161 uses unused zones)
+        * +-+  0-------8------16-------8------16
+        * | |  |       |       |       |       |
+        * |s|  | INPUT |       | INPUT |       |
+        * | |->|  ->   |unused |  ->   |unused |
+        * |r|  |CAPTURE|       | OUTPUT|       |
+        * | |  |  MIX  |       |  MIX  |       |
+        * |c|  8--------------------------------
+        * | |  |       |       |       |       |
+        * | |  |       |       |       |       |
+        * |g|  |unused |unused |unused |unused |
+        * | |  |       |       |       |       |
+        * |a|  |       |       |       |       |
+        * | |  16-------------------------------
+        * |i|  |       |       |       |       |
+        * | |  | PLAYBK|       | PLAYBK|       |
+        * |n|->|  ->   |unused |  ->   |unused |
+        * | |  |CAPTURE|       | OUTPUT|       |
+        * | |  |  MIX  |       |  MIX  |       |
+        * |a|  8--------------------------------
+        * |r|  |       |       |       |       |
+        * |r|  |       |       |       |       |
+        * |a|  |unused |unused |unused |unused |
+        * |y|  |       |       |       |       |
+        * | |  |       |       |       |       |
+        * +++  16--|---------------|------------
+        *      +---V---------------V-----------+
+        *      |  dest_mix_gain_enable array   |
+        *      +-------------------------------+
+        */
+       /* example : MixerMatrix of LoLa280
+        * +-+  0-------8-2
+        * | |  |       | |
+        * |s|  | INPUT | |     INPUT
+        * |r|->|  ->   | |      ->
+        * |c|  |CAPTURE| | <-  OUTPUT
+        * | |  |  MIX  | |      MIX
+        * |g|  8----------
+        * |a|  |       | |
+        * |i|  | PLAYBK| |     PLAYBACK
+        * |n|->|  ->   | |      ->
+        * | |  |CAPTURE| | <-  OUTPUT
+        * |a|  |  MIX  | |      MIX
+        * |r|  8---|----|-
+        * |r|  +---V----V-------------------+
+        * |a|  | dest_mix_gain_enable array |
+        * |y|  +----------------------------+
         */
        if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
            chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
@@ -192,6 +213,9 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid)
                (((1U << chip->mixer.dest_phys_outs) - 1)
                 << chip->mixer.dest_phys_out_ofs);
 
+       snd_printdd("Mixer src_mask=%x, dest_mask=%x\n",
+                   chip->mixer.src_mask, chip->mixer.dest_mask);
+
        return 0;
 }
 
@@ -202,12 +226,19 @@ static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
 
        if (!(chip->mixer.src_mask & (1 << id)))
                return -EINVAL;
-       writew(gain, &chip->mixer.array->src_gain[id]);
        oldval = val = readl(&chip->mixer.array->src_gain_enable);
        if (on)
                val |= (1 << id);
        else
                val &= ~(1 << id);
+       /* test if values unchanged */
+       if ((val == oldval) &&
+           (gain == readw(&chip->mixer.array->src_gain[id])))
+               return 0;
+
+       snd_printdd("lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n",
+                       id, gain, val);
+       writew(gain, &chip->mixer.array->src_gain[id]);
        writel(val, &chip->mixer.array->src_gain_enable);
        lola_codec_flush(chip);
        /* inform micro-controller about the new source gain */
@@ -269,6 +300,7 @@ static int lola_mixer_set_mapping_gain(struct lola *chip,
                                src, dest);
 }
 
+#if 0 /* not used */
 static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
                                     unsigned int mask, unsigned short *gains)
 {
@@ -289,6 +321,7 @@ static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
        return lola_codec_write(chip, chip->mixer.nid,
                                LOLA_VERB_SET_DESTINATION_GAIN, id, 0);
 }
+#endif /* not used */
 
 /*
  */
@@ -376,6 +409,8 @@ static int set_analog_volume(struct lola *chip, int dir,
                return 0;
        if (external_call)
                lola_codec_flush(chip);
+       snd_printdd("set_analog_volume (dir=%d idx=%d, volume=%d)\n",
+                       dir, idx, val);
        err = lola_codec_write(chip, pin->nid,
                               LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
        if (err < 0)
@@ -427,23 +462,40 @@ static int init_mixer_values(struct lola *chip)
 {
        int i;
 
-       /* all src on */
+       /* all sample rate converters on */
        lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false);
 
-       /* clear all matrix */
+       /* clear all mixer matrix settings */
        memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array));
-       /* set src gain to 0dB */
+       /* inform firmware about all updated matrix columns - capture part */
+       for (i = 0; i < chip->mixer.dest_stream_ins; i++)
+               lola_codec_write(chip, chip->mixer.nid,
+                                LOLA_VERB_SET_DESTINATION_GAIN,
+                                i, 0);
+       /* inform firmware about all updated matrix columns - output part */
+       for (i = 0; i < chip->mixer.dest_phys_outs; i++)
+               lola_codec_write(chip, chip->mixer.nid,
+                                LOLA_VERB_SET_DESTINATION_GAIN,
+                                chip->mixer.dest_phys_out_ofs + i, 0);
+
+       /* set all digital input source (master) gains to 0dB */
        for (i = 0; i < chip->mixer.src_phys_ins; i++)
                lola_mixer_set_src_gain(chip, i, 336, true); /* 0dB */
+
+       /* set all digital playback source (master) gains to 0dB */
        for (i = 0; i < chip->mixer.src_stream_outs; i++)
                lola_mixer_set_src_gain(chip,
                                        i + chip->mixer.src_stream_out_ofs,
                                        336, true); /* 0dB */
-       /* set 1:1 dest gain */
+       /* set gain value 0dB diagonally in matrix - part INPUT -> CAPTURE */
        for (i = 0; i < chip->mixer.dest_stream_ins; i++) {
                int src = i % chip->mixer.src_phys_ins;
                lola_mixer_set_mapping_gain(chip, src, i, 336, true);
        }
+       /* set gain value 0dB diagonally in matrix , part PLAYBACK -> OUTPUT
+        * (LoLa280 : playback channel 0,2,4,6 linked to output channel 0)
+        * (LoLa280 : playback channel 1,3,5,7 linked to output channel 1)
+        */
        for (i = 0; i < chip->mixer.src_stream_outs; i++) {
                int src = chip->mixer.src_stream_out_ofs + i;
                int dst = chip->mixer.dest_phys_out_ofs +
@@ -693,6 +745,7 @@ static int __devinit create_src_gain_mixer(struct lola *chip,
                           snd_ctl_new1(&lola_src_gain_mixer, chip));
 }
 
+#if 0 /* not used */
 /*
  * destination gain (matrix-like) mixer
  */
@@ -781,6 +834,7 @@ static int __devinit create_dest_gain_mixer(struct lola *chip,
        return snd_ctl_add(chip->card,
                          snd_ctl_new1(&lola_dest_gain_mixer, chip));
 }
+#endif /* not used */
 
 /*
  */
@@ -798,14 +852,16 @@ int __devinit lola_create_mixer(struct lola *chip)
        if (err < 0)
                return err;
        err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0,
-                                   "Line Source Gain Volume");
+                                   "Digital Capture Volume");
        if (err < 0)
                return err;
        err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs,
                                    chip->mixer.src_stream_out_ofs,
-                                   "Stream Source Gain Volume");
+                                   "Digital Playback Volume");
        if (err < 0)
                return err;
+#if 0
+/* FIXME: buggy mixer matrix handling */
        err = create_dest_gain_mixer(chip,
                                     chip->mixer.src_phys_ins, 0,
                                     chip->mixer.dest_stream_ins, 0,
@@ -834,6 +890,6 @@ int __devinit lola_create_mixer(struct lola *chip)
                                     "Stream Playback Volume");
        if (err < 0)
                return err;
-
+#endif /* FIXME */
        return init_mixer_values(chip);
 }
index 1bd7a54..04ae84b 100644 (file)
@@ -762,7 +762,6 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran)
 static int __devinit lx_init_dsp(struct lx6464es *chip)
 {
        int err;
-       u8 mac_address[6];
        int i;
 
        snd_printdd("->lx_init_dsp\n");
@@ -787,11 +786,11 @@ static int __devinit lx_init_dsp(struct lx6464es *chip)
        /** \todo the mac address should be ready by not, but it isn't,
         *  so we wait for it */
        for (i = 0; i != 1000; ++i) {
-               err = lx_dsp_get_mac(chip, mac_address);
+               err = lx_dsp_get_mac(chip);
                if (err)
                        return err;
-               if (mac_address[0] || mac_address[1] || mac_address[2] ||
-                   mac_address[3] || mac_address[4] || mac_address[5])
+               if (chip->mac_address[0] || chip->mac_address[1] || chip->mac_address[2] ||
+                   chip->mac_address[3] || chip->mac_address[4] || chip->mac_address[5])
                        goto mac_ready;
                msleep(1);
        }
@@ -800,8 +799,8 @@ static int __devinit lx_init_dsp(struct lx6464es *chip)
 mac_ready:
        snd_printd(LXP "mac address ready read after: %dms\n", i);
        snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n",
-                  mac_address[0], mac_address[1], mac_address[2],
-                  mac_address[3], mac_address[4], mac_address[5]);
+                  chip->mac_address[0], chip->mac_address[1], chip->mac_address[2],
+                  chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
 
        err = lx_init_get_version_features(chip);
        if (err)
@@ -1031,7 +1030,7 @@ static int __devinit snd_lx6464es_create(struct snd_card *card,
        chip->port_dsp_bar = pci_ioremap_bar(pci, 2);
 
        err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED,
-                         card_name, chip);
+                         KBUILD_MODNAME, chip);
        if (err) {
                snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq);
                goto request_irq_failed;
@@ -1108,8 +1107,14 @@ static int __devinit snd_lx6464es_probe(struct pci_dev *pci,
                goto out_free;
        }
 
-       strcpy(card->driver, "lx6464es");
-       strcpy(card->shortname, "Digigram LX6464ES");
+       strcpy(card->driver, "LX6464ES");
+       sprintf(card->id, "LX6464ES_%02X%02X%02X",
+               chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
+
+       sprintf(card->shortname, "LX6464ES %02X.%02X.%02X.%02X.%02X.%02X",
+               chip->mac_address[0], chip->mac_address[1], chip->mac_address[2],
+               chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
+
        sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i",
                card->shortname, chip->port_plx,
                chip->port_dsp_bar, chip->irq);
@@ -1137,7 +1142,7 @@ static void __devexit snd_lx6464es_remove(struct pci_dev *pci)
 
 
 static struct pci_driver driver = {
-       .name =     "Digigram LX6464ES",
+       .name =     KBUILD_MODNAME,
        .id_table = snd_lx6464es_ids,
        .probe =    snd_lx6464es_probe,
        .remove = __devexit_p(snd_lx6464es_remove),
index aea621e..e2a124a 100644 (file)
@@ -69,6 +69,8 @@ struct lx6464es {
        struct pci_dev         *pci;
        int                     irq;
 
+       u8                      mac_address[6];
+
        spinlock_t              lock;        /* interrupt spinlock */
        struct mutex            setup_mutex; /* mutex used in hw_params, open
                                              * and close */
index 617f98b..5c8717e 100644 (file)
@@ -424,7 +424,7 @@ int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
        return ret;
 }
 
-int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address)
+int lx_dsp_get_mac(struct lx6464es *chip)
 {
        u32 macmsb, maclsb;
 
@@ -432,12 +432,12 @@ int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address)
        maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF;
 
        /* todo: endianess handling */
-       mac_address[5] = ((u8 *)(&maclsb))[0];
-       mac_address[4] = ((u8 *)(&maclsb))[1];
-       mac_address[3] = ((u8 *)(&maclsb))[2];
-       mac_address[2] = ((u8 *)(&macmsb))[0];
-       mac_address[1] = ((u8 *)(&macmsb))[1];
-       mac_address[0] = ((u8 *)(&macmsb))[2];
+       chip->mac_address[5] = ((u8 *)(&maclsb))[0];
+       chip->mac_address[4] = ((u8 *)(&maclsb))[1];
+       chip->mac_address[3] = ((u8 *)(&maclsb))[2];
+       chip->mac_address[2] = ((u8 *)(&macmsb))[0];
+       chip->mac_address[1] = ((u8 *)(&macmsb))[1];
+       chip->mac_address[0] = ((u8 *)(&macmsb))[2];
 
        return 0;
 }
index 6bd9cbb..1dd5629 100644 (file)
@@ -116,7 +116,7 @@ int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version);
 int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq);
 int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran);
 int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data);
-int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address);
+int lx_dsp_get_mac(struct lx6464es *chip);
 
 
 /* low-level pipe handling */
index 3c40d72..0378126 100644 (file)
@@ -850,11 +850,10 @@ struct snd_m3 {
        struct input_dev *input_dev;
        char phys[64];                  /* physical device path */
 #else
-       spinlock_t ac97_lock;
        struct snd_kcontrol *master_switch;
        struct snd_kcontrol *master_volume;
-       struct tasklet_struct hwvol_tq;
 #endif
+       struct work_struct hwvol_work;
 
        unsigned int in_suspend;
 
@@ -1609,13 +1608,10 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s)
    (without wrap around) in response to volume button presses and then
    generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
    of a byte wide register. The meaning of bits 0 and 4 is unknown. */
-static void snd_m3_update_hw_volume(unsigned long private_data)
+static void snd_m3_update_hw_volume(struct work_struct *work)
 {
-       struct snd_m3 *chip = (struct snd_m3 *) private_data;
+       struct snd_m3 *chip = container_of(work, struct snd_m3, hwvol_work);
        int x, val;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
-       unsigned long flags;
-#endif
 
        /* Figure out which volume control button was pushed,
           based on differences from the default register
@@ -1645,21 +1641,13 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
        if (!chip->master_switch || !chip->master_volume)
                return;
 
-       /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
-       spin_lock_irqsave(&chip->ac97_lock, flags);
-
-       val = chip->ac97->regs[AC97_MASTER_VOL];
+       val = snd_ac97_read(chip->ac97, AC97_MASTER);
        switch (x) {
        case 0x88:
                /* The counters have not changed, yet we've received a HV
                   interrupt. According to tests run by various people this
                   happens when pressing the mute button. */
                val ^= 0x8000;
-               chip->ac97->regs[AC97_MASTER_VOL] = val;
-               outw(val, chip->iobase + CODEC_DATA);
-               outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
-               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                              &chip->master_switch->id);
                break;
        case 0xaa:
                /* counters increased by 1 -> volume up */
@@ -1667,11 +1655,6 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
                        val--;
                if ((val & 0x7f00) > 0)
                        val -= 0x0100;
-               chip->ac97->regs[AC97_MASTER_VOL] = val;
-               outw(val, chip->iobase + CODEC_DATA);
-               outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
-               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                              &chip->master_volume->id);
                break;
        case 0x66:
                /* counters decreased by 1 -> volume down */
@@ -1679,14 +1662,11 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
                        val++;
                if ((val & 0x7f00) < 0x1f00)
                        val += 0x0100;
-               chip->ac97->regs[AC97_MASTER_VOL] = val;
-               outw(val, chip->iobase + CODEC_DATA);
-               outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
-               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                              &chip->master_volume->id);
                break;
        }
-       spin_unlock_irqrestore(&chip->ac97_lock, flags);
+       if (snd_ac97_update(chip->ac97, AC97_MASTER, val))
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &chip->master_switch->id);
 #else
        if (!chip->input_dev)
                return;
@@ -1730,11 +1710,7 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
                return IRQ_NONE;
 
        if (status & HV_INT_PENDING)
-#ifdef CONFIG_SND_MAESTRO3_INPUT
-               snd_m3_update_hw_volume((unsigned long)chip);
-#else
-               tasklet_schedule(&chip->hwvol_tq);
-#endif
+               schedule_work(&chip->hwvol_work);
 
        /*
         * ack an assp int if its running
@@ -2000,24 +1976,14 @@ static unsigned short
 snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
        struct snd_m3 *chip = ac97->private_data;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
-       unsigned long flags;
-#endif
        unsigned short data = 0xffff;
 
        if (snd_m3_ac97_wait(chip))
                goto fail;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
-       spin_lock_irqsave(&chip->ac97_lock, flags);
-#endif
        snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
        if (snd_m3_ac97_wait(chip))
-               goto fail_unlock;
+               goto fail;
        data = snd_m3_inw(chip, CODEC_DATA);
-fail_unlock:
-#ifndef CONFIG_SND_MAESTRO3_INPUT
-       spin_unlock_irqrestore(&chip->ac97_lock, flags);
-#endif
 fail:
        return data;
 }
@@ -2026,20 +1992,11 @@ static void
 snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
 {
        struct snd_m3 *chip = ac97->private_data;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
-       unsigned long flags;
-#endif
 
        if (snd_m3_ac97_wait(chip))
                return;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
-       spin_lock_irqsave(&chip->ac97_lock, flags);
-#endif
        snd_m3_outw(chip, val, CODEC_DATA);
        snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
-#ifndef CONFIG_SND_MAESTRO3_INPUT
-       spin_unlock_irqrestore(&chip->ac97_lock, flags);
-#endif
 }
 
 
@@ -2458,6 +2415,7 @@ static int snd_m3_free(struct snd_m3 *chip)
        struct m3_dma *s;
        int i;
 
+       cancel_work_sync(&chip->hwvol_work);
 #ifdef CONFIG_SND_MAESTRO3_INPUT
        if (chip->input_dev)
                input_unregister_device(chip->input_dev);
@@ -2511,6 +2469,7 @@ static int m3_suspend(struct pci_dev *pci, pm_message_t state)
                return 0;
 
        chip->in_suspend = 1;
+       cancel_work_sync(&chip->hwvol_work);
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        snd_pcm_suspend_all(chip->pcm);
        snd_ac97_suspend(chip->ac97);
@@ -2667,9 +2626,6 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
        }
 
        spin_lock_init(&chip->reg_lock);
-#ifndef CONFIG_SND_MAESTRO3_INPUT
-       spin_lock_init(&chip->ac97_lock);
-#endif
 
        switch (pci->device) {
        case PCI_DEVICE_ID_ESS_ALLEGRO:
@@ -2683,6 +2639,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
+       INIT_WORK(&chip->hwvol_work, snd_m3_update_hw_volume);
 
        chip->external_amp = enable_amp;
        if (amp_gpio >= 0 && amp_gpio <= 0x0f)
@@ -2752,12 +2709,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
 
        snd_m3_hv_init(chip);
 
-#ifndef CONFIG_SND_MAESTRO3_INPUT
-       tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
-#endif
-
        if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
-                       card->driver, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_m3_free(chip);
                return -ENOMEM;
@@ -2885,7 +2838,7 @@ static void __devexit snd_m3_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "Maestro3",
+       .name = KBUILD_MODNAME,
        .id_table = snd_m3_ids,
        .probe = snd_m3_probe,
        .remove = __devexit_p(snd_m3_remove),
index 6c3fd4d..dbee599 100644 (file)
@@ -1268,7 +1268,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci,
        }
 
        if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED,
-                       CARD_NAME, mgr)) {
+                       KBUILD_MODNAME, mgr)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_mixart_free(mgr);
                return -EBUSY;
@@ -1381,7 +1381,7 @@ static void __devexit snd_mixart_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "Digigram miXart",
+       .name = KBUILD_MODNAME,
        .id_table = snd_mixart_ids,
        .probe = snd_mixart_probe,
        .remove = __devexit_p(snd_mixart_remove),
index 5a60492..83ea7a7 100644 (file)
@@ -465,7 +465,7 @@ static int snd_nm256_acquire_irq(struct nm256 *chip)
        mutex_lock(&chip->irq_mutex);
        if (chip->irq < 0) {
                if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED,
-                               chip->card->driver, chip)) {
+                               KBUILD_MODNAME, chip)) {
                        snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq);
                        mutex_unlock(&chip->irq_mutex);
                        return -EBUSY;
@@ -1743,7 +1743,7 @@ static void __devexit snd_nm256_remove(struct pci_dev *pci)
 
 
 static struct pci_driver driver = {
-       .name = "NeoMagic 256",
+       .name = KBUILD_MODNAME,
        .id_table = snd_nm256_ids,
        .probe = snd_nm256_probe,
        .remove = __devexit_p(snd_nm256_remove),
index d7e8ddd..218d985 100644 (file)
@@ -859,7 +859,7 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci,
 }
 
 static struct pci_driver oxygen_driver = {
-       .name = "CMI8788",
+       .name = KBUILD_MODNAME,
        .id_table = oxygen_ids,
        .probe = generic_oxygen_probe,
        .remove = __devexit_p(oxygen_pci_remove),
index 70b7398..82311fc 100644 (file)
@@ -655,7 +655,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        chip->model.init(chip);
 
        err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED,
-                         DRIVER, chip);
+                         KBUILD_MODNAME, chip);
        if (err < 0) {
                snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq);
                goto err_card;
index d5533e3..cc0bcd9 100644 (file)
@@ -168,12 +168,6 @@ static int oxygen_open(struct snd_pcm_substream *substream,
                if (err < 0)
                        return err;
        }
-       if (channel == PCM_MULTICH) {
-               err = snd_pcm_hw_constraint_minmax
-                       (runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 0, 8192000);
-               if (err < 0)
-                       return err;
-       }
        snd_pcm_set_sync(substream);
        chip->streams[channel] = substream;
 
index 469010a..773db79 100644 (file)
@@ -88,7 +88,7 @@ static int __devinit xonar_probe(struct pci_dev *pci,
 }
 
 static struct pci_driver xonar_driver = {
-       .name = "AV200",
+       .name = KBUILD_MODNAME,
        .id_table = xonar_ids,
        .probe = xonar_probe,
        .remove = __devexit_p(oxygen_pci_remove),
index 54cad38..32d096c 100644 (file)
@@ -327,8 +327,10 @@ static void pcm1796_init(struct oxygen *chip)
 {
        struct xonar_pcm179x *data = chip->model_data;
 
-       data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE |
+       data->pcm1796_regs[0][18 - PCM1796_REG_BASE] =
                PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;
+       if (!data->broken_i2c)
+               data->pcm1796_regs[0][18 - PCM1796_REG_BASE] |= PCM1796_MUTE;
        data->pcm1796_regs[0][19 - PCM1796_REG_BASE] =
                PCM1796_FLT_SHARP | PCM1796_ATS_1;
        data->pcm1796_regs[0][20 - PCM1796_REG_BASE] =
@@ -1123,6 +1125,7 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
                        chip->model.control_filter = xonar_st_h6_control_filter;
                        chip->model.dac_channels_pcm = 8;
                        chip->model.dac_channels_mixer = 8;
+                       chip->model.dac_volume_min = 255;
                        chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
                        break;
                }
index 95cfde2..046578d 100644 (file)
@@ -1501,7 +1501,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci,
        mgr->irq = -1;
 
        if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED,
-                       card_name, mgr)) {
+                       KBUILD_MODNAME, mgr)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                pcxhr_free(mgr);
                return -EBUSY;
@@ -1608,7 +1608,7 @@ static void __devexit pcxhr_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "Digigram pcxhr",
+       .name = KBUILD_MODNAME,
        .id_table = pcxhr_ids,
        .probe = pcxhr_probe,
        .remove = __devexit_p(pcxhr_remove),
index ad5202e..e34ae14 100644 (file)
@@ -1890,7 +1890,7 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci,
        UNSET_AIE(hwport);
 
        if (request_irq(pci->irq, snd_riptide_interrupt, IRQF_SHARED,
-                       "RIPTIDE", chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "Riptide: unable to grab IRQ %d\n",
                           pci->irq);
                snd_riptide_free(chip);
@@ -2176,7 +2176,7 @@ static void __devexit snd_card_riptide_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "RIPTIDE",
+       .name = KBUILD_MODNAME,
        .id_table = snd_riptide_ids,
        .probe = snd_card_riptide_probe,
        .remove = __devexit_p(snd_card_riptide_remove),
@@ -2188,7 +2188,7 @@ static struct pci_driver driver = {
 
 #ifdef SUPPORT_JOYSTICK
 static struct pci_driver joystick_driver = {
-       .name = "Riptide Joystick",
+       .name = KBUILD_MODNAME "-joystick",
        .id_table = snd_riptide_joystick_ids,
        .probe = snd_riptide_joystick_probe,
        .remove = __devexit_p(snd_riptide_joystick_remove),
index 3c04524..6be77a2 100644 (file)
@@ -1355,7 +1355,7 @@ static int __devinit snd_rme32_create(struct rme32 * rme32)
        }
 
        if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED,
-                       "RME32", rme32)) {
+                       KBUILD_MODNAME, rme32)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                return -EBUSY;
        }
@@ -1985,7 +1985,7 @@ static void __devexit snd_rme32_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name =         "RME Digi32",
+       .name =         KBUILD_MODNAME,
        .id_table =     snd_rme32_ids,
        .probe =        snd_rme32_probe,
        .remove =       __devexit_p(snd_rme32_remove),
index 9ff247f..409e5b8 100644 (file)
@@ -1561,7 +1561,7 @@ snd_rme96_create(struct rme96 *rme96)
        }
 
        if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_SHARED,
-                       "RME96", rme96)) {
+                       KBUILD_MODNAME, rme96)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                return -EBUSY;
        }
@@ -2396,7 +2396,7 @@ static void __devexit snd_rme96_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "RME Digi96",
+       .name = KBUILD_MODNAME,
        .id_table = snd_rme96_ids,
        .probe = snd_rme96_probe,
        .remove = __devexit_p(snd_rme96_remove),
index 2d83324..1c6d1e1 100644 (file)
@@ -5482,7 +5482,7 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
        }
 
        if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_SHARED,
-                       "hdsp", hdsp)) {
+                       KBUILD_MODNAME, hdsp)) {
                snd_printk(KERN_ERR "Hammerfall-DSP: unable to use IRQ %d\n", pci->irq);
                return -EBUSY;
        }
@@ -5637,7 +5637,7 @@ static void __devexit snd_hdsp_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name =     "RME Hammerfall DSP",
+       .name =     KBUILD_MODNAME,
        .id_table = snd_hdsp_ids,
        .probe =    snd_hdsp_probe,
        .remove = __devexit_p(snd_hdsp_remove),
index c8e402f..af130ee 100644 (file)
@@ -6441,7 +6441,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card,
                        hdspm->port + io_extent - 1);
 
        if (request_irq(pci->irq, snd_hdspm_interrupt,
-                               IRQF_SHARED, "hdspm", hdspm)) {
+                       IRQF_SHARED, KBUILD_MODNAME, hdspm)) {
                snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq);
                return -EBUSY;
        }
@@ -6779,7 +6779,7 @@ static void __devexit snd_hdspm_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "RME Hammerfall DSP MADI",
+       .name = KBUILD_MODNAME,
        .id_table = snd_hdspm_ids,
        .probe = snd_hdspm_probe,
        .remove = __devexit_p(snd_hdspm_remove),
index c492af5..1c7bc1e 100644 (file)
@@ -2479,7 +2479,7 @@ static int __devinit snd_rme9652_create(struct snd_card *card,
        }
        
        if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_SHARED,
-                       "rme9652", rme9652)) {
+                       KBUILD_MODNAME, rme9652)) {
                snd_printk(KERN_ERR "unable to request IRQ %d\n", pci->irq);
                return -EBUSY;
        }
@@ -2632,7 +2632,7 @@ static void __devexit snd_rme9652_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name     = "RME Digi9652 (Hammerfall)",
+       .name     = KBUILD_MODNAME,
        .id_table = snd_rme9652_ids,
        .probe    = snd_rme9652_probe,
        .remove   = __devexit_p(snd_rme9652_remove),
index 2b5c7a9..bcf6152 100644 (file)
@@ -1235,7 +1235,7 @@ static int sis_resume(struct pci_dev *pci)
        }
 
        if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
-                               card->shortname, sis)) {
+                       KBUILD_MODNAME, sis)) {
                printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq);
                goto error;
        }
@@ -1341,7 +1341,7 @@ static int __devinit sis_chip_create(struct snd_card *card,
                goto error_out_cleanup;
 
        if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
-                               card->shortname, sis)) {
+                       KBUILD_MODNAME, sis)) {
                printk(KERN_ERR "unable to allocate irq %d\n", sis->irq);
                goto error_out_cleanup;
        }
@@ -1436,7 +1436,7 @@ static void __devexit snd_sis7019_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver sis7019_driver = {
-       .name = "SiS7019",
+       .name = KBUILD_MODNAME,
        .id_table = snd_sis7019_ids,
        .probe = snd_sis7019_probe,
        .remove = __devexit_p(snd_sis7019_remove),
index 337b9fa..2571a67 100644 (file)
@@ -1294,7 +1294,7 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card,
        sonic->game_port = pci_resource_start(pci, 4);
 
        if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_SHARED,
-                       "S3 SonicVibes", sonic)) {
+                       KBUILD_MODNAME, sonic)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_sonicvibes_free(sonic);
                return -EBUSY;
@@ -1530,7 +1530,7 @@ static void __devexit snd_sonic_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "S3 SonicVibes",
+       .name = KBUILD_MODNAME,
        .id_table = snd_sonic_ids,
        .probe = snd_sonic_probe,
        .remove = __devexit_p(snd_sonic_remove),
index 6d05818..d8a128f 100644 (file)
@@ -172,7 +172,7 @@ static void __devexit snd_trident_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "Trident4DWaveAudio",
+       .name = KBUILD_MODNAME,
        .id_table = snd_trident_ids,
        .probe = snd_trident_probe,
        .remove = __devexit_p(snd_trident_remove),
index 2870a4f..5bd57a7 100644 (file)
@@ -3598,7 +3598,7 @@ int __devinit snd_trident_create(struct snd_card *card,
        trident->port = pci_resource_start(pci, 0);
 
        if (request_irq(pci->irq, snd_trident_interrupt, IRQF_SHARED,
-                       "Trident Audio", trident)) {
+                       KBUILD_MODNAME, trident)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_trident_free(trident);
                return -EBUSY;
index 8c5f8b5..f03fd62 100644 (file)
@@ -2377,7 +2377,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card,
                        chip_type == TYPE_VIA8233 ?
                        snd_via8233_interrupt : snd_via686_interrupt,
                        IRQF_SHARED,
-                       card->driver, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_via82xx_free(chip);
                return -EBUSY;
@@ -2611,7 +2611,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "VIA 82xx Audio",
+       .name = KBUILD_MODNAME,
        .id_table = snd_via82xx_ids,
        .probe = snd_via82xx_probe,
        .remove = __devexit_p(snd_via82xx_remove),
index f7e8bbb..a386dd9 100644 (file)
@@ -1129,7 +1129,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card,
        }
        chip->port = pci_resource_start(pci, 0);
        if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED,
-                       card->driver, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_via82xx_free(chip);
                return -EBUSY;
@@ -1224,7 +1224,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "VIA 82xx Modem",
+       .name = KBUILD_MODNAME,
        .id_table = snd_via82xx_modem_ids,
        .probe = snd_via82xx_probe,
        .remove = __devexit_p(snd_via82xx_remove),
index 99a9a81..5342d5e 100644 (file)
@@ -169,7 +169,7 @@ static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci
                vx->port[i] = pci_resource_start(pci, i + 1);
 
        if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED,
-                       CARD_NAME, chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_vx222_free(chip);
                return -EBUSY;
@@ -290,7 +290,7 @@ static int snd_vx222_resume(struct pci_dev *pci)
 #endif
 
 static struct pci_driver driver = {
-       .name = "Digigram VX222",
+       .name = KBUILD_MODNAME,
        .id_table = snd_vx222_ids,
        .probe = snd_vx222_probe,
        .remove = __devexit_p(snd_vx222_remove),
index 80c6821..511d576 100644 (file)
@@ -345,7 +345,7 @@ static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver driver = {
-       .name = "Yamaha DS-1 PCI",
+       .name = KBUILD_MODNAME,
        .id_table = snd_ymfpci_ids,
        .probe = snd_card_ymfpci_probe,
        .remove = __devexit_p(snd_card_ymfpci_remove),
index c94c051..f3260e6 100644 (file)
@@ -2380,7 +2380,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
                return -EBUSY;
        }
        if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_SHARED,
-                       "YMFPCI", chip)) {
+                       KBUILD_MODNAME, chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_ymfpci_free(chip);
                return -EBUSY;
index ce33be0..66488a7 100644 (file)
@@ -223,7 +223,7 @@ static int pdacf_config(struct pcmcia_device *link)
        if (ret)
                goto failed;
 
-       ret = pcmcia_request_exclusive_irq(link, pdacf_interrupt);
+       ret = pcmcia_request_irq(link, pdacf_interrupt);
        if (ret)
                goto failed;
 
index d9ef21d..31777d1 100644 (file)
@@ -229,7 +229,7 @@ static int vxpocket_config(struct pcmcia_device *link)
        if (ret)
                goto failed;
 
-       ret = pcmcia_request_exclusive_irq(link, snd_vx_irq_handler);
+       ret = pcmcia_request_irq(link, snd_vx_irq_handler);
        if (ret)
                goto failed;
 
index 1ed61c5..4f91387 100644 (file)
@@ -1,4 +1,5 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
+snd-soc-core-objs += soc-pcm.o soc-io.o
 
 obj-$(CONFIG_SND_SOC)  += snd-soc-core.o
 obj-$(CONFIG_SND_SOC)  += codecs/
index d0e7532..f81d4c3 100644 (file)
@@ -364,9 +364,11 @@ static struct snd_pcm_ops atmel_pcm_ops = {
 \*--------------------------------------------------------------------------*/
 static u64 atmel_pcm_dmamask = 0xffffffff;
 
-static int atmel_pcm_new(struct snd_card *card,
-       struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        if (!card->dev->dma_mask)
@@ -382,7 +384,7 @@ static int atmel_pcm_new(struct snd_card *card,
        }
 
        if (dai->driver->capture.channels_min) {
-               pr_debug("at32-pcm:"
+               pr_debug("atmel-pcm:"
                                "Allocating PCM capture DMA buffer\n");
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
index 2597329..5e0a95e 100644 (file)
@@ -60,7 +60,7 @@ struct atmel_ssc_mask {
  * This structure, shared between the PCM driver and the interface,
  * contains all information required by the PCM driver to perform the
  * PDC DMA operation.  All fields except dma_intr_handler() are initialized
- * by the interface.  The dms_intr_handler() pointer is set by the PCM
+ * by the interface.  The dma_intr_handler() pointer is set by the PCM
  * driver and called by the interface SSC interrupt handler if it is
  * non-NULL.
  */
index eda955b..7122509 100644 (file)
@@ -402,7 +402,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S
                && bits > 16) {
                printk(KERN_WARNING
-                               "atmel_ssc_dai: sample size %d"
+                               "atmel_ssc_dai: sample size %d "
                                "is too large for I2S\n", bits);
                return -EINVAL;
        }
@@ -838,10 +838,8 @@ int atmel_ssc_set_audio(int ssc_id)
        }
 
        ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
-       if (!ssc_pdev) {
-               ssc_free(ssc);
+       if (!ssc_pdev)
                return -ENOMEM;
-       }
 
        /* If we can grab the SSC briefly to parent the DAI device off it */
        ssc = ssc_request(ssc_id);
index 95572d2..bad3aa1 100644 (file)
@@ -92,6 +92,7 @@ static struct snd_soc_ops at91sam9g20ek_ops = {
 };
 
 static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
+                                       struct snd_soc_dapm_context *dapm,
                                        enum snd_soc_bias_level level)
 {
        static int mclk_on;
index 10fdd28..20bb53a 100644 (file)
@@ -319,10 +319,11 @@ static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm)
        snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
-static int au1xpsc_pcm_new(struct snd_card *card,
-                          struct snd_soc_dai *dai,
-                          struct snd_pcm *pcm)
+static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_pcm *pcm = rtd->pcm;
+
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1);
 
index ae40359..fe9d548 100644 (file)
@@ -10,13 +10,36 @@ config SND_BF5XX_I2S
 
 config SND_BF5XX_SOC_SSM2602
        tristate "SoC SSM2602 Audio support for BF52x ezkit"
-       depends on SND_BF5XX_I2S
+       depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
        select SND_BF5XX_SOC_I2S
        select SND_SOC_SSM2602
-       select I2C
        help
          Say Y if you want to add support for SoC audio on BF527-EZKIT.
 
+config SND_SOC_BFIN_EVAL_ADAU1701
+       tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
+       depends on SND_BF5XX_I2S
+       select SND_BF5XX_SOC_I2S
+       select SND_SOC_ADAU1701
+       select I2C
+       help
+         Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ
+         board connected to one of the Blackfin evaluation boards like the
+         BF5XX-STAMP or BF5XX-EZKIT.
+
+config SND_SOC_BFIN_EVAL_ADAV80X
+       tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
+       depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+       select SND_BF5XX_SOC_I2S
+       select SND_SOC_ADAV80X
+       help
+         Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or
+         EVAL-ADAV803 board connected to one of the Blackfin evaluation boards
+         like the BF5XX-STAMP or BF5XX-EZKIT.
+
+         Note: This driver assumes that the ADAV80X digital record and playback
+         interfaces are connected to the first SPORT port on the BF5XX board.
+
 config SND_BF5XX_SOC_AD73311
        tristate "SoC AD73311 Audio support for Blackfin"
        depends on SND_BF5XX_I2S
index 49af3f3..6018bf5 100644 (file)
@@ -21,9 +21,13 @@ snd-ad1980-objs := bf5xx-ad1980.o
 snd-ssm2602-objs := bf5xx-ssm2602.o
 snd-ad73311-objs := bf5xx-ad73311.o
 snd-ad193x-objs := bf5xx-ad193x.o
+snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o
+snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o
 
 obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o
 obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
 obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
 obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
 obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o
+obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o
+obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o
index 98b44b3..9e59f68 100644 (file)
@@ -418,9 +418,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 
-int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm)
+int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        pr_debug("%s enter\n", __func__);
index f1fd95b..61ddf94 100644 (file)
@@ -168,7 +168,7 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 
        snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 
-       ret = snd_pcm_hw_constraint_integer(runtime, \
+       ret = snd_pcm_hw_constraint_integer(runtime,
                        SNDRV_PCM_HW_PARAM_PERIODS);
        if (ret < 0)
                goto out;
@@ -257,9 +257,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 
-int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm)
+int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        pr_debug("%s enter\n", __func__);
@@ -304,8 +306,8 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_i2s_pcm_driver = {
        .driver = {
-                       .name = "bfin-i2s-pcm-audio",
-                       .owner = THIS_MODULE,
+               .name = "bfin-i2s-pcm-audio",
+               .owner = THIS_MODULE,
        },
 
        .probe = bfin_i2s_soc_platform_probe,
index 07cfc7a..c95cc03 100644 (file)
@@ -283,9 +283,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 
-static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm)
+static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        if (!card->dev->dma_mask)
diff --git a/sound/soc/blackfin/bfin-eval-adau1701.c b/sound/soc/blackfin/bfin-eval-adau1701.c
new file mode 100644 (file)
index 0000000..e5550ac
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Machine driver for EVAL-ADAU1701MINIZ on Analog Devices bfin
+ * evaluation boards.
+ *
+ * Copyright 2011 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "../codecs/adau1701.h"
+
+static const struct snd_soc_dapm_widget bfin_eval_adau1701_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route bfin_eval_adau1701_dapm_routes[] = {
+       { "Speaker", NULL, "OUT0" },
+       { "Speaker", NULL, "OUT1" },
+       { "Line Out", NULL, "OUT2" },
+       { "Line Out", NULL, "OUT3" },
+
+       { "IN0", NULL, "Line In" },
+       { "IN1", NULL, "Line In" },
+};
+
+static int bfin_eval_adau1701_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000,
+                       SND_SOC_CLOCK_IN);
+
+       return ret;
+}
+
+static struct snd_soc_ops bfin_eval_adau1701_ops = {
+       .hw_params = bfin_eval_adau1701_hw_params,
+};
+
+static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = {
+       {
+               .name = "adau1701",
+               .stream_name = "adau1701",
+               .cpu_dai_name = "bfin-i2s.0",
+               .codec_dai_name = "adau1701",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "adau1701.0-0034",
+               .ops = &bfin_eval_adau1701_ops,
+       },
+       {
+               .name = "adau1701",
+               .stream_name = "adau1701",
+               .cpu_dai_name = "bfin-i2s.1",
+               .codec_dai_name = "adau1701",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "adau1701.0-0034",
+               .ops = &bfin_eval_adau1701_ops,
+       },
+};
+
+static struct snd_soc_card bfin_eval_adau1701 = {
+       .name = "bfin-eval-adau1701",
+       .dai_link = &bfin_eval_adau1701_dai[CONFIG_SND_BF5XX_SPORT_NUM],
+       .num_links = 1,
+
+       .dapm_widgets           = bfin_eval_adau1701_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(bfin_eval_adau1701_dapm_widgets),
+       .dapm_routes            = bfin_eval_adau1701_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(bfin_eval_adau1701_dapm_routes),
+};
+
+static int bfin_eval_adau1701_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &bfin_eval_adau1701;
+
+       card->dev = &pdev->dev;
+
+       return snd_soc_register_card(&bfin_eval_adau1701);
+}
+
+static int __devexit bfin_eval_adau1701_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static struct platform_driver bfin_eval_adau1701_driver = {
+       .driver = {
+               .name = "bfin-eval-adau1701",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = bfin_eval_adau1701_probe,
+       .remove = __devexit_p(bfin_eval_adau1701_remove),
+};
+
+static int __init bfin_eval_adau1701_init(void)
+{
+       return platform_driver_register(&bfin_eval_adau1701_driver);
+}
+module_init(bfin_eval_adau1701_init);
+
+static void __exit bfin_eval_adau1701_exit(void)
+{
+       platform_driver_unregister(&bfin_eval_adau1701_driver);
+}
+module_exit(bfin_eval_adau1701_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ALSA SoC bfin ADAU1701 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bfin-eval-adau1701");
diff --git a/sound/soc/blackfin/bfin-eval-adav80x.c b/sound/soc/blackfin/bfin-eval-adav80x.c
new file mode 100644 (file)
index 0000000..8d014d0
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Machine driver for EVAL-ADAV801 and EVAL-ADAV803 on Analog Devices bfin
+ * evaluation boards.
+ *
+ * Copyright 2011 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "../codecs/adav80x.h"
+
+static const struct snd_soc_dapm_widget bfin_eval_adav80x_dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("Line Out", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route bfin_eval_adav80x_dapm_routes[] = {
+       { "Line Out", NULL, "VOUTL" },
+       { "Line Out", NULL, "VOUTR" },
+
+       { "VINL", NULL, "Line In" },
+       { "VINR", NULL, "Line In" },
+};
+
+static int bfin_eval_adav80x_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_PLL1, ADAV80X_PLL_SRC_XTAL,
+                       27000000, params_rate(params) * 256);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_PLL1,
+                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
+
+       return ret;
+}
+
+static int bfin_eval_adav80x_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK1, 0,
+           SND_SOC_CLOCK_OUT);
+       snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK2, 0,
+           SND_SOC_CLOCK_OUT);
+       snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK3, 0,
+           SND_SOC_CLOCK_OUT);
+
+       snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_XTAL, 2700000, 0);
+
+       return 0;
+}
+
+static struct snd_soc_ops bfin_eval_adav80x_ops = {
+       .hw_params = bfin_eval_adav80x_hw_params,
+};
+
+static struct snd_soc_dai_link bfin_eval_adav80x_dais[] = {
+       {
+               .name = "adav80x",
+               .stream_name = "ADAV80x HiFi",
+               .cpu_dai_name = "bfin-i2s.0",
+               .codec_dai_name = "adav80x-hifi",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .init = bfin_eval_adav80x_codec_init,
+               .ops = &bfin_eval_adav80x_ops,
+       },
+};
+
+static struct snd_soc_card bfin_eval_adav80x = {
+       .name = "bfin-eval-adav80x",
+       .dai_link = bfin_eval_adav80x_dais,
+       .num_links = ARRAY_SIZE(bfin_eval_adav80x_dais),
+
+       .dapm_widgets           = bfin_eval_adav80x_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(bfin_eval_adav80x_dapm_widgets),
+       .dapm_routes            = bfin_eval_adav80x_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(bfin_eval_adav80x_dapm_routes),
+};
+
+enum bfin_eval_adav80x_type {
+       BFIN_EVAL_ADAV801,
+       BFIN_EVAL_ADAV803,
+};
+
+static int bfin_eval_adav80x_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &bfin_eval_adav80x;
+       const char *codec_name;
+
+       switch (platform_get_device_id(pdev)->driver_data) {
+       case BFIN_EVAL_ADAV801:
+               codec_name = "spi0.1";
+               break;
+       case BFIN_EVAL_ADAV803:
+               codec_name = "adav803.0-0034";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       bfin_eval_adav80x_dais[0].codec_name = codec_name;
+
+       card->dev = &pdev->dev;
+
+       return snd_soc_register_card(&bfin_eval_adav80x);
+}
+
+static int __devexit bfin_eval_adav80x_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static const struct platform_device_id bfin_eval_adav80x_ids[] = {
+       { "bfin-eval-adav801", BFIN_EVAL_ADAV801 },
+       { "bfin-eval-adav803", BFIN_EVAL_ADAV803 },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, bfin_eval_adav80x_ids);
+
+static struct platform_driver bfin_eval_adav80x_driver = {
+       .driver = {
+               .name = "bfin-eval-adav80x",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = bfin_eval_adav80x_probe,
+       .remove = __devexit_p(bfin_eval_adav80x_remove),
+       .id_table = bfin_eval_adav80x_ids,
+};
+
+static int __init bfin_eval_adav80x_init(void)
+{
+       return platform_driver_register(&bfin_eval_adav80x_driver);
+}
+module_init(bfin_eval_adav80x_init);
+
+static void __exit bfin_eval_adav80x_exit(void)
+{
+       platform_driver_unregister(&bfin_eval_adav80x_driver);
+}
+module_exit(bfin_eval_adav80x_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ALSA SoC bfin adav80x driver");
+MODULE_LICENSE("GPL");
index 98175a0..36a030f 100644 (file)
@@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
        select SND_SOC_AD1980 if SND_SOC_AC97_BUS
        select SND_SOC_AD73311
+       select SND_SOC_ADAV80X
        select SND_SOC_ADS117X
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
@@ -42,6 +43,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_SN95031 if INTEL_SCU_IPC
        select SND_SOC_SPDIF
        select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_STA32X if I2C
        select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
        select SND_SOC_TLV320AIC23 if I2C
        select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -71,6 +73,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8770 if SPI_MASTER
        select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_WM8782
        select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
@@ -84,6 +87,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8971 if I2C
        select SND_SOC_WM8974 if I2C
        select SND_SOC_WM8978 if I2C
+       select SND_SOC_WM8983 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8990 if I2C
@@ -130,7 +134,14 @@ config SND_SOC_AD1980
 
 config SND_SOC_AD73311
        tristate
-       
+
+config SND_SOC_ADAU1701
+       select SIGMA
+       tristate
+
+config SND_SOC_ADAV80X
+       tristate
+
 config SND_SOC_ADS117X
        tristate
 
@@ -216,6 +227,9 @@ config SND_SOC_SPDIF
 config SND_SOC_SSM2602
        tristate
 
+config SND_SOC_STA32X
+       tristate
+
 config SND_SOC_STAC9766
        tristate
 
@@ -299,6 +313,9 @@ config SND_SOC_WM8770
 config SND_SOC_WM8776
        tristate
 
+config SND_SOC_WM8782
+       tristate
+
 config SND_SOC_WM8804
        tristate
 
@@ -338,6 +355,9 @@ config SND_SOC_WM8974
 config SND_SOC_WM8978
        tristate
 
+config SND_SOC_WM8983
+       tristate
+
 config SND_SOC_WM8985
        tristate
 
index fd85584..da9990f 100644 (file)
@@ -4,6 +4,8 @@ snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad193x-objs := ad193x.o
 snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
+snd-soc-adau1701-objs := adau1701.o
+snd-soc-adav80x-objs := adav80x.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
@@ -28,6 +30,7 @@ snd-soc-alc5623-objs := alc5623.o
 snd-soc-sn95031-objs := sn95031.o
 snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-sta32x-objs := sta32x.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
@@ -55,6 +58,7 @@ snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8770-objs := wm8770.o
 snd-soc-wm8776-objs := wm8776.o
+snd-soc-wm8782-objs := wm8782.o
 snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
@@ -68,6 +72,7 @@ snd-soc-wm8962-objs := wm8962.o
 snd-soc-wm8971-objs := wm8971.o
 snd-soc-wm8974-objs := wm8974.o
 snd-soc-wm8978-objs := wm8978.o
+snd-soc-wm8983-objs := wm8983.o
 snd-soc-wm8985-objs := wm8985.o
 snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
@@ -95,6 +100,8 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD193X)   += snd-soc-ad193x.o
 obj-$(CONFIG_SND_SOC_AD1980)   += snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_ADAU1701)  += snd-soc-adau1701.o
+obj-$(CONFIG_SND_SOC_ADAV80X)  += snd-soc-adav80x.o
 obj-$(CONFIG_SND_SOC_ADS117X)  += snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)   += snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
@@ -120,6 +127,7 @@ obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SN95031)  +=snd-soc-sn95031.o
 obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
@@ -147,6 +155,7 @@ obj-$(CONFIG_SND_SOC_WM8750)        += snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)   += snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8770)   += snd-soc-wm8770.o
 obj-$(CONFIG_SND_SOC_WM8776)   += snd-soc-wm8776.o
+obj-$(CONFIG_SND_SOC_WM8782)   += snd-soc-wm8782.o
 obj-$(CONFIG_SND_SOC_WM8804)   += snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
@@ -160,6 +169,7 @@ obj-$(CONFIG_SND_SOC_WM8962)        += snd-soc-wm8962.o
 obj-$(CONFIG_SND_SOC_WM8971)   += snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8974)   += snd-soc-wm8974.o
 obj-$(CONFIG_SND_SOC_WM8978)   += snd-soc-wm8978.o
+obj-$(CONFIG_SND_SOC_WM8983)   += snd-soc-wm8983.o
 obj-$(CONFIG_SND_SOC_WM8985)   += snd-soc-wm8985.o
 obj-$(CONFIG_SND_SOC_WM8988)   += snd-soc-wm8988.o
 obj-$(CONFIG_SND_SOC_WM8990)   += snd-soc-wm8990.o
index 754c496..4e5c572 100644 (file)
@@ -1,19 +1,10 @@
-/*
- * File:         sound/soc/codecs/ad1836.c
- * Author:       Barry Song <Barry.Song@analog.com>
- *
- * Created:      Aug 04 2009
- * Description:  Driver for AD1836 sound chip
- *
- * Modified:
- *               Copyright 2009 Analog Devices Inc.
+ /*
+ * Audio Codec driver supporting:
+ *  AD1835A, AD1836, AD1837A, AD1838A, AD1839A
  *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ * Copyright 2009-2011 Analog Devices Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/init.h>
 #include <linux/spi/spi.h>
 #include "ad1836.h"
 
+enum ad1836_type {
+       AD1835,
+       AD1836,
+       AD1838,
+};
+
 /* codec private data */
 struct ad1836_priv {
-       enum snd_soc_control_type control_type;
-       void *control_data;
+       enum ad1836_type type;
 };
 
 /*
@@ -44,29 +40,60 @@ static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"};
 static const struct soc_enum ad1836_deemp_enum =
        SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp);
 
-static const struct snd_kcontrol_new ad1836_snd_controls[] = {
-       /* DAC volume control */
-       SOC_DOUBLE_R("DAC1 Volume", AD1836_DAC_L1_VOL,
-                       AD1836_DAC_R1_VOL, 0, 0x3FF, 0),
-       SOC_DOUBLE_R("DAC2 Volume", AD1836_DAC_L2_VOL,
-                       AD1836_DAC_R2_VOL, 0, 0x3FF, 0),
-       SOC_DOUBLE_R("DAC3 Volume", AD1836_DAC_L3_VOL,
-                       AD1836_DAC_R3_VOL, 0, 0x3FF, 0),
-
-       /* ADC switch control */
-       SOC_DOUBLE("ADC1 Switch", AD1836_ADC_CTRL2, AD1836_ADCL1_MUTE,
-               AD1836_ADCR1_MUTE, 1, 1),
-       SOC_DOUBLE("ADC2 Switch", AD1836_ADC_CTRL2, AD1836_ADCL2_MUTE,
-               AD1836_ADCR2_MUTE, 1, 1),
-
-       /* DAC switch control */
-       SOC_DOUBLE("DAC1 Switch", AD1836_DAC_CTRL2, AD1836_DACL1_MUTE,
-               AD1836_DACR1_MUTE, 1, 1),
-       SOC_DOUBLE("DAC2 Switch", AD1836_DAC_CTRL2, AD1836_DACL2_MUTE,
-               AD1836_DACR2_MUTE, 1, 1),
-       SOC_DOUBLE("DAC3 Switch", AD1836_DAC_CTRL2, AD1836_DACL3_MUTE,
-               AD1836_DACR3_MUTE, 1, 1),
+#define AD1836_DAC_VOLUME(x) \
+       SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \
+                       AD1836_DAC_R_VOL(x), 0, 0x3FF, 0)
+
+#define AD1836_DAC_SWITCH(x) \
+       SOC_DOUBLE("DAC" #x " Playback Switch", AD1836_DAC_CTRL2, \
+                       AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1)
+
+#define AD1836_ADC_SWITCH(x) \
+       SOC_DOUBLE("ADC" #x " Capture Switch", AD1836_ADC_CTRL2, \
+               AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1)
+
+static const struct snd_kcontrol_new ad183x_dac_controls[] = {
+       AD1836_DAC_VOLUME(1),
+       AD1836_DAC_SWITCH(1),
+       AD1836_DAC_VOLUME(2),
+       AD1836_DAC_SWITCH(2),
+       AD1836_DAC_VOLUME(3),
+       AD1836_DAC_SWITCH(3),
+       AD1836_DAC_VOLUME(4),
+       AD1836_DAC_SWITCH(4),
+};
+
+static const struct snd_soc_dapm_widget ad183x_dac_dapm_widgets[] = {
+       SND_SOC_DAPM_OUTPUT("DAC1OUT"),
+       SND_SOC_DAPM_OUTPUT("DAC2OUT"),
+       SND_SOC_DAPM_OUTPUT("DAC3OUT"),
+       SND_SOC_DAPM_OUTPUT("DAC4OUT"),
+};
+
+static const struct snd_soc_dapm_route ad183x_dac_routes[] = {
+       { "DAC1OUT", NULL, "DAC" },
+       { "DAC2OUT", NULL, "DAC" },
+       { "DAC3OUT", NULL, "DAC" },
+       { "DAC4OUT", NULL, "DAC" },
+};
+
+static const struct snd_kcontrol_new ad183x_adc_controls[] = {
+       AD1836_ADC_SWITCH(1),
+       AD1836_ADC_SWITCH(2),
+       AD1836_ADC_SWITCH(3),
+};
+
+static const struct snd_soc_dapm_widget ad183x_adc_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("ADC1IN"),
+       SND_SOC_DAPM_INPUT("ADC2IN"),
+};
+
+static const struct snd_soc_dapm_route ad183x_adc_routes[] = {
+       { "ADC", NULL, "ADC1IN" },
+       { "ADC", NULL, "ADC2IN" },
+};
 
+static const struct snd_kcontrol_new ad183x_controls[] = {
        /* ADC high-pass filter */
        SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1,
                        AD1836_ADC_HIGHPASS_FILTER, 1, 0),
@@ -75,27 +102,24 @@ static const struct snd_kcontrol_new ad1836_snd_controls[] = {
        SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum),
 };
 
-static const struct snd_soc_dapm_widget ad1836_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = {
        SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1,
                                AD1836_DAC_POWERDOWN, 1),
        SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1,
                                AD1836_ADC_POWERDOWN, 1, NULL, 0),
-       SND_SOC_DAPM_OUTPUT("DAC1OUT"),
-       SND_SOC_DAPM_OUTPUT("DAC2OUT"),
-       SND_SOC_DAPM_OUTPUT("DAC3OUT"),
-       SND_SOC_DAPM_INPUT("ADC1IN"),
-       SND_SOC_DAPM_INPUT("ADC2IN"),
 };
 
-static const struct snd_soc_dapm_route audio_paths[] = {
+static const struct snd_soc_dapm_route ad183x_dapm_routes[] = {
        { "DAC", NULL, "ADC_PWR" },
        { "ADC", NULL, "ADC_PWR" },
-       { "DAC1OUT", "DAC1 Switch", "DAC" },
-       { "DAC2OUT", "DAC2 Switch", "DAC" },
-       { "DAC3OUT", "DAC3 Switch", "DAC" },
-       { "ADC", "ADC1 Switch", "ADC1IN" },
-       { "ADC", "ADC2 Switch", "ADC2IN" },
+};
+
+static const DECLARE_TLV_DB_SCALE(ad1836_in_tlv, 0, 300, 0);
+
+static const struct snd_kcontrol_new ad1836_controls[] = {
+       SOC_DOUBLE_TLV("ADC2 Capture Volume", AD1836_ADC_CTRL1, 3, 0, 4, 0,
+           ad1836_in_tlv),
 };
 
 /*
@@ -165,64 +189,69 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static struct snd_soc_dai_ops ad1836_dai_ops = {
+       .hw_params = ad1836_hw_params,
+       .set_fmt = ad1836_set_dai_fmt,
+};
+
+#define AD183X_DAI(_name, num_dacs, num_adcs) \
+{ \
+       .name = _name "-hifi", \
+       .playback = { \
+               .stream_name = "Playback", \
+               .channels_min = 2, \
+               .channels_max = (num_dacs) * 2, \
+               .rates = SNDRV_PCM_RATE_48000,  \
+               .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
+       }, \
+       .capture = { \
+               .stream_name = "Capture", \
+               .channels_min = 2, \
+               .channels_max = (num_adcs) * 2, \
+               .rates = SNDRV_PCM_RATE_48000, \
+               .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
+       }, \
+       .ops = &ad1836_dai_ops, \
+}
+
+static struct snd_soc_dai_driver ad183x_dais[] = {
+       [AD1835] = AD183X_DAI("ad1835", 4, 1),
+       [AD1836] = AD183X_DAI("ad1836", 3, 2),
+       [AD1838] = AD183X_DAI("ad1838", 3, 1),
+};
+
 #ifdef CONFIG_PM
-static int ad1836_soc_suspend(struct snd_soc_codec *codec,
-               pm_message_t state)
+static int ad1836_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
        /* reset clock control mode */
-       u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
-       adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
-
-       return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
+       return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+               AD1836_ADC_SERFMT_MASK, 0);
 }
 
-static int ad1836_soc_resume(struct snd_soc_codec *codec)
+static int ad1836_resume(struct snd_soc_codec *codec)
 {
        /* restore clock control mode */
-       u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
-       adc_ctrl2 |= AD1836_ADC_AUX;
-
-       return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
+       return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+               AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX);
 }
 #else
-#define ad1836_soc_suspend NULL
-#define ad1836_soc_resume  NULL
+#define ad1836_suspend NULL
+#define ad1836_resume  NULL
 #endif
 
-static struct snd_soc_dai_ops ad1836_dai_ops = {
-       .hw_params = ad1836_hw_params,
-       .set_fmt = ad1836_set_dai_fmt,
-};
-
-/* codec DAI instance */
-static struct snd_soc_dai_driver ad1836_dai = {
-       .name = "ad1836-hifi",
-       .playback = {
-               .stream_name = "Playback",
-               .channels_min = 2,
-               .channels_max = 6,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
-                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
-       },
-       .capture = {
-               .stream_name = "Capture",
-               .channels_min = 2,
-               .channels_max = 4,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
-                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
-       },
-       .ops = &ad1836_dai_ops,
-};
-
 static int ad1836_probe(struct snd_soc_codec *codec)
 {
        struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int num_dacs, num_adcs;
        int ret = 0;
+       int i;
+
+       num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2;
+       num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2;
 
-       codec->control_data = ad1836->control_data;
        ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
        if (ret < 0) {
                dev_err(codec->dev, "failed to set cache I/O: %d\n",
@@ -239,21 +268,46 @@ static int ad1836_probe(struct snd_soc_codec *codec)
        snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100);
        /* unmute adc channles, adc aux mode */
        snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180);
-       /* left/right diff:PGA/MUX */
-       snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
        /* volume */
-       snd_soc_write(codec, AD1836_DAC_L1_VOL, 0x3FF);
-       snd_soc_write(codec, AD1836_DAC_R1_VOL, 0x3FF);
-       snd_soc_write(codec, AD1836_DAC_L2_VOL, 0x3FF);
-       snd_soc_write(codec, AD1836_DAC_R2_VOL, 0x3FF);
-       snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF);
-       snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF);
-
-       snd_soc_add_controls(codec, ad1836_snd_controls,
-                            ARRAY_SIZE(ad1836_snd_controls));
-       snd_soc_dapm_new_controls(dapm, ad1836_dapm_widgets,
-                                 ARRAY_SIZE(ad1836_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
+       for (i = 1; i <= num_dacs; ++i) {
+               snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF);
+               snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF);
+       }
+
+       if (ad1836->type == AD1836) {
+               /* left/right diff:PGA/MUX */
+               snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
+               ret = snd_soc_add_controls(codec, ad1836_controls,
+                               ARRAY_SIZE(ad1836_controls));
+               if (ret)
+                       return ret;
+       } else {
+               snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00);
+       }
+
+       ret = snd_soc_add_controls(codec, ad183x_dac_controls, num_dacs * 2);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_add_controls(codec, ad183x_adc_controls, num_adcs);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dapm_new_controls(dapm, ad183x_dac_dapm_widgets, num_dacs);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dapm_new_controls(dapm, ad183x_adc_dapm_widgets, num_adcs);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dapm_add_routes(dapm, ad183x_dac_routes, num_dacs);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs);
+       if (ret)
+               return ret;
 
        return ret;
 }
@@ -262,19 +316,24 @@ static int ad1836_probe(struct snd_soc_codec *codec)
 static int ad1836_remove(struct snd_soc_codec *codec)
 {
        /* reset clock control mode */
-       u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
-       adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
-
-       return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
+       return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+               AD1836_ADC_SERFMT_MASK, 0);
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
-       .probe =        ad1836_probe,
-       .remove =       ad1836_remove,
-       .suspend =      ad1836_soc_suspend,
-       .resume =       ad1836_soc_resume,
+       .probe = ad1836_probe,
+       .remove = ad1836_remove,
+       .suspend = ad1836_suspend,
+       .resume = ad1836_resume,
        .reg_cache_size = AD1836_NUM_REGS,
        .reg_word_size = sizeof(u16),
+
+       .controls = ad183x_controls,
+       .num_controls = ARRAY_SIZE(ad183x_controls),
+       .dapm_widgets = ad183x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets),
+       .dapm_routes = ad183x_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes),
 };
 
 static int __devinit ad1836_spi_probe(struct spi_device *spi)
@@ -286,12 +345,12 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi)
        if (ad1836 == NULL)
                return -ENOMEM;
 
+       ad1836->type = spi_get_device_id(spi)->driver_data;
+
        spi_set_drvdata(spi, ad1836);
-       ad1836->control_data = spi;
-       ad1836->control_type = SND_SOC_SPI;
 
        ret = snd_soc_register_codec(&spi->dev,
-                       &soc_codec_dev_ad1836, &ad1836_dai, 1);
+                       &soc_codec_dev_ad1836, &ad183x_dais[ad1836->type], 1);
        if (ret < 0)
                kfree(ad1836);
        return ret;
@@ -303,27 +362,29 @@ static int __devexit ad1836_spi_remove(struct spi_device *spi)
        kfree(spi_get_drvdata(spi));
        return 0;
 }
+static const struct spi_device_id ad1836_ids[] = {
+       { "ad1835", AD1835 },
+       { "ad1836", AD1836 },
+       { "ad1837", AD1835 },
+       { "ad1838", AD1838 },
+       { "ad1839", AD1838 },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, ad1836_ids);
 
 static struct spi_driver ad1836_spi_driver = {
        .driver = {
-               .name   = "ad1836-codec",
+               .name   = "ad1836",
                .owner  = THIS_MODULE,
        },
        .probe          = ad1836_spi_probe,
        .remove         = __devexit_p(ad1836_spi_remove),
+       .id_table       = ad1836_ids,
 };
 
 static int __init ad1836_init(void)
 {
-       int ret;
-
-       ret = spi_register_driver(&ad1836_spi_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register ad1836 SPI driver: %d\n",
-                               ret);
-       }
-
-       return ret;
+       return spi_register_driver(&ad1836_spi_driver);
 }
 module_init(ad1836_init);
 
index 9d6a3f8..444747f 100644 (file)
@@ -1,19 +1,10 @@
 /*
- * File:         sound/soc/codecs/ad1836.h
- * Based on:
- * Author:       Barry Song <Barry.Song@analog.com>
+ * Audio Codec driver supporting:
+ *  AD1835A, AD1836, AD1837A, AD1838A, AD1839A
  *
- * Created:      Aug 04, 2009
- * Description:  definitions for AD1836 registers
+ * Copyright 2009-2011 Analog Devices Inc.
  *
- * Modified:
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Licensed under the GPL-2 or later.
  */
 
 #ifndef __AD1836_H__
 
 #define AD1836_DAC_CTRL1               0
 #define AD1836_DAC_POWERDOWN           2
-#define AD1836_DAC_SERFMT_MASK        0xE0
+#define AD1836_DAC_SERFMT_MASK         0xE0
 #define AD1836_DAC_SERFMT_PCK256       (0x4 << 5)
 #define AD1836_DAC_SERFMT_PCK128       (0x5 << 5)
 #define AD1836_DAC_WORD_LEN_MASK       0x18
 #define AD1836_DAC_WORD_LEN_OFFSET     3
 
 #define AD1836_DAC_CTRL2               1
-#define AD1836_DACL1_MUTE              0
-#define AD1836_DACR1_MUTE              1
-#define AD1836_DACL2_MUTE              2
-#define AD1836_DACR2_MUTE              3
-#define AD1836_DACL3_MUTE              4
-#define AD1836_DACR3_MUTE              5
 
-#define AD1836_DAC_L1_VOL              2
-#define AD1836_DAC_R1_VOL              3
-#define AD1836_DAC_L2_VOL              4
-#define AD1836_DAC_R2_VOL              5
-#define AD1836_DAC_L3_VOL              6
-#define AD1836_DAC_R3_VOL              7
+/* These macros are one-based. So AD183X_MUTE_LEFT(1) will return the mute bit
+ * for the first ADC/DAC */
+#define AD1836_MUTE_LEFT(x) (((x) * 2) - 2)
+#define AD1836_MUTE_RIGHT(x) (((x) * 2) - 1)
+
+#define AD1836_DAC_L_VOL(x) ((x) * 2)
+#define AD1836_DAC_R_VOL(x) (1 + ((x) * 2))
 
 #define AD1836_ADC_CTRL1               12
 #define AD1836_ADC_POWERDOWN           7
 #define AD1836_ADC_HIGHPASS_FILTER     8
 
 #define AD1836_ADC_CTRL2               13
-#define AD1836_ADCL1_MUTE              0
-#define AD1836_ADCR1_MUTE              1
-#define AD1836_ADCL2_MUTE              2
-#define AD1836_ADCR2_MUTE              3
 #define AD1836_ADC_WORD_LEN_MASK       0x30
 #define AD1836_ADC_WORD_OFFSET         5
-#define AD1836_ADC_SERFMT_MASK        (7 << 6)
+#define AD1836_ADC_SERFMT_MASK         (7 << 6)
 #define AD1836_ADC_SERFMT_PCK256       (0x4 << 6)
 #define AD1836_ADC_SERFMT_PCK128       (0x5 << 6)
 #define AD1836_ADC_AUX                 (0x6 << 6)
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
new file mode 100644 (file)
index 0000000..2758d5f
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * Driver for ADAU1701 SigmaDSP processor
+ *
+ * Copyright 2011 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *     based on an inital version by Cliff Cai <cliff.cai@analog.com>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/sigma.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "adau1701.h"
+
+#define ADAU1701_DSPCTRL       0x1c
+#define ADAU1701_SEROCTL       0x1e
+#define ADAU1701_SERICTL       0x1f
+
+#define ADAU1701_AUXNPOW       0x22
+
+#define ADAU1701_OSCIPOW       0x26
+#define ADAU1701_DACSET                0x27
+
+#define ADAU1701_NUM_REGS      0x28
+
+#define ADAU1701_DSPCTRL_CR            (1 << 2)
+#define ADAU1701_DSPCTRL_DAM           (1 << 3)
+#define ADAU1701_DSPCTRL_ADM           (1 << 4)
+#define ADAU1701_DSPCTRL_SR_48         0x00
+#define ADAU1701_DSPCTRL_SR_96         0x01
+#define ADAU1701_DSPCTRL_SR_192                0x02
+#define ADAU1701_DSPCTRL_SR_MASK       0x03
+
+#define ADAU1701_SEROCTL_INV_LRCLK     0x2000
+#define ADAU1701_SEROCTL_INV_BCLK      0x1000
+#define ADAU1701_SEROCTL_MASTER                0x0800
+
+#define ADAU1701_SEROCTL_OBF16         0x0000
+#define ADAU1701_SEROCTL_OBF8          0x0200
+#define ADAU1701_SEROCTL_OBF4          0x0400
+#define ADAU1701_SEROCTL_OBF2          0x0600
+#define ADAU1701_SEROCTL_OBF_MASK      0x0600
+
+#define ADAU1701_SEROCTL_OLF1024       0x0000
+#define ADAU1701_SEROCTL_OLF512                0x0080
+#define ADAU1701_SEROCTL_OLF256                0x0100
+#define ADAU1701_SEROCTL_OLF_MASK      0x0180
+
+#define ADAU1701_SEROCTL_MSB_DEALY1    0x0000
+#define ADAU1701_SEROCTL_MSB_DEALY0    0x0004
+#define ADAU1701_SEROCTL_MSB_DEALY8    0x0008
+#define ADAU1701_SEROCTL_MSB_DEALY12   0x000c
+#define ADAU1701_SEROCTL_MSB_DEALY16   0x0010
+#define ADAU1701_SEROCTL_MSB_DEALY_MASK        0x001c
+
+#define ADAU1701_SEROCTL_WORD_LEN_24   0x0000
+#define ADAU1701_SEROCTL_WORD_LEN_20   0x0001
+#define ADAU1701_SEROCTL_WORD_LEN_16   0x0010
+#define ADAU1701_SEROCTL_WORD_LEN_MASK 0x0003
+
+#define ADAU1701_AUXNPOW_VBPD          0x40
+#define ADAU1701_AUXNPOW_VRPD          0x20
+
+#define ADAU1701_SERICTL_I2S           0
+#define ADAU1701_SERICTL_LEFTJ         1
+#define ADAU1701_SERICTL_TDM           2
+#define ADAU1701_SERICTL_RIGHTJ_24     3
+#define ADAU1701_SERICTL_RIGHTJ_20     4
+#define ADAU1701_SERICTL_RIGHTJ_18     5
+#define ADAU1701_SERICTL_RIGHTJ_16     6
+#define ADAU1701_SERICTL_MODE_MASK     7
+#define ADAU1701_SERICTL_INV_BCLK      BIT(3)
+#define ADAU1701_SERICTL_INV_LRCLK     BIT(4)
+
+#define ADAU1701_OSCIPOW_OPD           0x04
+#define ADAU1701_DACSET_DACINIT                1
+
+#define ADAU1701_FIRMWARE "adau1701.bin"
+
+struct adau1701 {
+       unsigned int dai_fmt;
+};
+
+static const struct snd_kcontrol_new adau1701_controls[] = {
+       SOC_SINGLE("Master Capture Switch", ADAU1701_DSPCTRL, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget adau1701_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC0", "Playback", ADAU1701_AUXNPOW, 3, 1),
+       SND_SOC_DAPM_DAC("DAC1", "Playback", ADAU1701_AUXNPOW, 2, 1),
+       SND_SOC_DAPM_DAC("DAC2", "Playback", ADAU1701_AUXNPOW, 1, 1),
+       SND_SOC_DAPM_DAC("DAC3", "Playback", ADAU1701_AUXNPOW, 0, 1),
+       SND_SOC_DAPM_ADC("ADC", "Capture", ADAU1701_AUXNPOW, 7, 1),
+
+       SND_SOC_DAPM_OUTPUT("OUT0"),
+       SND_SOC_DAPM_OUTPUT("OUT1"),
+       SND_SOC_DAPM_OUTPUT("OUT2"),
+       SND_SOC_DAPM_OUTPUT("OUT3"),
+       SND_SOC_DAPM_INPUT("IN0"),
+       SND_SOC_DAPM_INPUT("IN1"),
+};
+
+static const struct snd_soc_dapm_route adau1701_dapm_routes[] = {
+       { "OUT0", NULL, "DAC0" },
+       { "OUT1", NULL, "DAC1" },
+       { "OUT2", NULL, "DAC2" },
+       { "OUT3", NULL, "DAC3" },
+
+       { "ADC", NULL, "IN0" },
+       { "ADC", NULL, "IN1" },
+};
+
+static unsigned int adau1701_register_size(struct snd_soc_codec *codec,
+               unsigned int reg)
+{
+       switch (reg) {
+       case ADAU1701_DSPCTRL:
+       case ADAU1701_SEROCTL:
+       case ADAU1701_AUXNPOW:
+       case ADAU1701_OSCIPOW:
+       case ADAU1701_DACSET:
+               return 2;
+       case ADAU1701_SERICTL:
+               return 1;
+       }
+
+       dev_err(codec->dev, "Unsupported register address: %d\n", reg);
+       return 0;
+}
+
+static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg,
+               unsigned int value)
+{
+       unsigned int i;
+       unsigned int size;
+       uint8_t buf[4];
+       int ret;
+
+       size = adau1701_register_size(codec, reg);
+       if (size == 0)
+               return -EINVAL;
+
+       snd_soc_cache_write(codec, reg, value);
+
+       buf[0] = 0x08;
+       buf[1] = reg;
+
+       for (i = size + 1; i >= 2; --i) {
+               buf[i] = value;
+               value >>= 8;
+       }
+
+       ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2);
+       if (ret == size + 2)
+               return 0;
+       else if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       unsigned int value;
+       unsigned int ret;
+
+       ret = snd_soc_cache_read(codec, reg, &value);
+       if (ret)
+               return ret;
+
+       return value;
+}
+
+static int adau1701_load_firmware(struct snd_soc_codec *codec)
+{
+       return process_sigma_firmware(codec->control_data, ADAU1701_FIRMWARE);
+}
+
+static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
+               snd_pcm_format_t format)
+{
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+       unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK;
+       unsigned int val;
+
+       switch (format) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               val = ADAU1701_SEROCTL_WORD_LEN_16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val = ADAU1701_SEROCTL_WORD_LEN_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val = ADAU1701_SEROCTL_WORD_LEN_24;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) {
+               switch (format) {
+               case SNDRV_PCM_FORMAT_S16_LE:
+                       val |= ADAU1701_SEROCTL_MSB_DEALY16;
+                       break;
+               case SNDRV_PCM_FORMAT_S20_3LE:
+                       val |= ADAU1701_SEROCTL_MSB_DEALY12;
+                       break;
+               case SNDRV_PCM_FORMAT_S24_LE:
+                       val |= ADAU1701_SEROCTL_MSB_DEALY8;
+                       break;
+               }
+               mask |= ADAU1701_SEROCTL_MSB_DEALY_MASK;
+       }
+
+       snd_soc_update_bits(codec, ADAU1701_SEROCTL, mask, val);
+
+       return 0;
+}
+
+static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
+                       snd_pcm_format_t format)
+{
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val;
+
+       if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
+               return 0;
+
+       switch (format) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               val = ADAU1701_SERICTL_RIGHTJ_16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val = ADAU1701_SERICTL_RIGHTJ_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val = ADAU1701_SERICTL_RIGHTJ_24;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, ADAU1701_SERICTL,
+               ADAU1701_SERICTL_MODE_MASK, val);
+
+       return 0;
+}
+
+static int adau1701_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       snd_pcm_format_t format;
+       unsigned int val;
+
+       switch (params_rate(params)) {
+       case 192000:
+               val = ADAU1701_DSPCTRL_SR_192;
+               break;
+       case 96000:
+               val = ADAU1701_DSPCTRL_SR_96;
+               break;
+       case 48000:
+               val = ADAU1701_DSPCTRL_SR_48;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, ADAU1701_DSPCTRL,
+               ADAU1701_DSPCTRL_SR_MASK, val);
+
+       format = params_format(params);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return adau1701_set_playback_pcm_format(codec, format);
+       else
+               return adau1701_set_capture_pcm_format(codec, format);
+}
+
+static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+       unsigned int serictl = 0x00, seroctl = 0x00;
+       bool invert_lrclk;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /* master, 64-bits per sample, 1 frame per sample */
+               seroctl |= ADAU1701_SEROCTL_MASTER | ADAU1701_SEROCTL_OBF16
+                               | ADAU1701_SEROCTL_OLF1024;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               invert_lrclk = false;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               invert_lrclk = true;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               invert_lrclk = false;
+               serictl |= ADAU1701_SERICTL_INV_BCLK;
+               seroctl |= ADAU1701_SEROCTL_INV_BCLK;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               invert_lrclk = true;
+               serictl |= ADAU1701_SERICTL_INV_BCLK;
+               seroctl |= ADAU1701_SEROCTL_INV_BCLK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               serictl |= ADAU1701_SERICTL_LEFTJ;
+               seroctl |= ADAU1701_SEROCTL_MSB_DEALY0;
+               invert_lrclk = !invert_lrclk;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               serictl |= ADAU1701_SERICTL_RIGHTJ_24;
+               seroctl |= ADAU1701_SEROCTL_MSB_DEALY8;
+               invert_lrclk = !invert_lrclk;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (invert_lrclk) {
+               seroctl |= ADAU1701_SEROCTL_INV_LRCLK;
+               serictl |= ADAU1701_SERICTL_INV_LRCLK;
+       }
+
+       adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+       snd_soc_write(codec, ADAU1701_SERICTL, serictl);
+       snd_soc_update_bits(codec, ADAU1701_SEROCTL,
+               ~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl);
+
+       return 0;
+}
+
+static int adau1701_set_bias_level(struct snd_soc_codec *codec,
+               enum snd_soc_bias_level level)
+{
+       unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* Enable VREF and VREF buffer */
+               snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, 0x00);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* Disable VREF and VREF buffer */
+               snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, mask);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int mask = ADAU1701_DSPCTRL_DAM;
+       unsigned int val;
+
+       if (mute)
+               val = 0;
+       else
+               val = mask;
+
+       snd_soc_update_bits(codec, ADAU1701_DSPCTRL, mask, val);
+
+       return 0;
+}
+
+static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+       unsigned int freq, int dir)
+{
+       unsigned int val;
+
+       switch (clk_id) {
+       case ADAU1701_CLK_SRC_OSC:
+               val = 0x0;
+               break;
+       case ADAU1701_CLK_SRC_MCLK:
+               val = ADAU1701_OSCIPOW_OPD;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val);
+
+       return 0;
+}
+
+#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
+       SNDRV_PCM_RATE_192000)
+
+#define ADAU1701_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+       SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops adau1701_dai_ops = {
+       .set_fmt        = adau1701_set_dai_fmt,
+       .hw_params      = adau1701_hw_params,
+       .digital_mute   = adau1701_digital_mute,
+};
+
+static struct snd_soc_dai_driver adau1701_dai = {
+       .name = "adau1701",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = ADAU1701_RATES,
+               .formats = ADAU1701_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = ADAU1701_RATES,
+               .formats = ADAU1701_FORMATS,
+       },
+       .ops = &adau1701_dai_ops,
+       .symmetric_rates = 1,
+};
+
+static int adau1701_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+
+       codec->dapm.idle_bias_off = 1;
+
+       ret = adau1701_load_firmware(codec);
+       if (ret)
+               dev_warn(codec->dev, "Failed to load firmware\n");
+
+       snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
+       snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver adau1701_codec_drv = {
+       .probe                  = adau1701_probe,
+       .set_bias_level         = adau1701_set_bias_level,
+
+       .reg_cache_size         = ADAU1701_NUM_REGS,
+       .reg_word_size          = sizeof(u16),
+
+       .controls               = adau1701_controls,
+       .num_controls           = ARRAY_SIZE(adau1701_controls),
+       .dapm_widgets           = adau1701_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(adau1701_dapm_widgets),
+       .dapm_routes            = adau1701_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(adau1701_dapm_routes),
+
+       .write                  = adau1701_write,
+       .read                   = adau1701_read,
+
+       .set_sysclk             = adau1701_set_sysclk,
+};
+
+static __devinit int adau1701_i2c_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct adau1701 *adau1701;
+       int ret;
+
+       adau1701 = kzalloc(sizeof(*adau1701), GFP_KERNEL);
+       if (!adau1701)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, adau1701);
+       ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
+                       &adau1701_dai, 1);
+       if (ret < 0)
+               kfree(adau1701);
+
+       return ret;
+}
+
+static __devexit int adau1701_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id adau1701_i2c_id[] = {
+       { "adau1701", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
+
+static struct i2c_driver adau1701_i2c_driver = {
+       .driver = {
+               .name   = "adau1701",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = adau1701_i2c_probe,
+       .remove         = __devexit_p(adau1701_i2c_remove),
+       .id_table       = adau1701_i2c_id,
+};
+
+static int __init adau1701_init(void)
+{
+       return i2c_add_driver(&adau1701_i2c_driver);
+}
+module_init(adau1701_init);
+
+static void __exit adau1701_exit(void)
+{
+       i2c_del_driver(&adau1701_i2c_driver);
+}
+module_exit(adau1701_exit);
+
+MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver");
+MODULE_AUTHOR("Cliff Cai <cliff.cai@analog.com>");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1701.h b/sound/soc/codecs/adau1701.h
new file mode 100644 (file)
index 0000000..8d0949a
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * header file for ADAU1701 SigmaDSP processor
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADAU1701_H
+#define _ADAU1701_H
+
+enum adau1701_clk_src {
+       ADAU1701_CLK_SRC_OSC,
+       ADAU1701_CLK_SRC_MCLK,
+};
+
+#endif
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
new file mode 100644 (file)
index 0000000..300c04b
--- /dev/null
@@ -0,0 +1,951 @@
+/*
+ * ADAV80X Audio Codec driver supporting ADAV801, ADAV803
+ *
+ * Copyright 2011 Analog Devices Inc.
+ * Author: Yi Li <yi.li@analog.com>
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+
+#include "adav80x.h"
+
+#define ADAV80X_PLAYBACK_CTRL  0x04
+#define ADAV80X_AUX_IN_CTRL    0x05
+#define ADAV80X_REC_CTRL       0x06
+#define ADAV80X_AUX_OUT_CTRL   0x07
+#define ADAV80X_DPATH_CTRL1    0x62
+#define ADAV80X_DPATH_CTRL2    0x63
+#define ADAV80X_DAC_CTRL1      0x64
+#define ADAV80X_DAC_CTRL2      0x65
+#define ADAV80X_DAC_CTRL3      0x66
+#define ADAV80X_DAC_L_VOL      0x68
+#define ADAV80X_DAC_R_VOL      0x69
+#define ADAV80X_PGA_L_VOL      0x6c
+#define ADAV80X_PGA_R_VOL      0x6d
+#define ADAV80X_ADC_CTRL1      0x6e
+#define ADAV80X_ADC_CTRL2      0x6f
+#define ADAV80X_ADC_L_VOL      0x70
+#define ADAV80X_ADC_R_VOL      0x71
+#define ADAV80X_PLL_CTRL1      0x74
+#define ADAV80X_PLL_CTRL2      0x75
+#define ADAV80X_ICLK_CTRL1     0x76
+#define ADAV80X_ICLK_CTRL2     0x77
+#define ADAV80X_PLL_CLK_SRC    0x78
+#define ADAV80X_PLL_OUTE       0x7a
+
+#define ADAV80X_PLL_CLK_SRC_PLL_XIN(pll)       0x00
+#define ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll)     (0x40 << (pll))
+#define ADAV80X_PLL_CLK_SRC_PLL_MASK(pll)      (0x40 << (pll))
+
+#define ADAV80X_ICLK_CTRL1_DAC_SRC(src)                ((src) << 5)
+#define ADAV80X_ICLK_CTRL1_ADC_SRC(src)                ((src) << 2)
+#define ADAV80X_ICLK_CTRL1_ICLK2_SRC(src)      (src)
+#define ADAV80X_ICLK_CTRL2_ICLK1_SRC(src)      ((src) << 3)
+
+#define ADAV80X_PLL_CTRL1_PLLDIV               0x10
+#define ADAV80X_PLL_CTRL1_PLLPD(pll)           (0x04 << (pll))
+#define ADAV80X_PLL_CTRL1_XTLPD                        0x02
+
+#define ADAV80X_PLL_CTRL2_FIELD(pll, x)                ((x) << ((pll) * 4))
+
+#define ADAV80X_PLL_CTRL2_FS_48(pll)   ADAV80X_PLL_CTRL2_FIELD((pll), 0x00)
+#define ADAV80X_PLL_CTRL2_FS_32(pll)   ADAV80X_PLL_CTRL2_FIELD((pll), 0x08)
+#define ADAV80X_PLL_CTRL2_FS_44(pll)   ADAV80X_PLL_CTRL2_FIELD((pll), 0x0c)
+
+#define ADAV80X_PLL_CTRL2_SEL(pll)     ADAV80X_PLL_CTRL2_FIELD((pll), 0x02)
+#define ADAV80X_PLL_CTRL2_DOUB(pll)    ADAV80X_PLL_CTRL2_FIELD((pll), 0x01)
+#define ADAV80X_PLL_CTRL2_PLL_MASK(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0f)
+
+#define ADAV80X_ADC_CTRL1_MODULATOR_MASK       0x80
+#define ADAV80X_ADC_CTRL1_MODULATOR_128FS      0x00
+#define ADAV80X_ADC_CTRL1_MODULATOR_64FS       0x80
+
+#define ADAV80X_DAC_CTRL1_PD                   0x80
+
+#define ADAV80X_DAC_CTRL2_DIV1                 0x00
+#define ADAV80X_DAC_CTRL2_DIV1_5               0x10
+#define ADAV80X_DAC_CTRL2_DIV2                 0x20
+#define ADAV80X_DAC_CTRL2_DIV3                 0x30
+#define ADAV80X_DAC_CTRL2_DIV_MASK             0x30
+
+#define ADAV80X_DAC_CTRL2_INTERPOL_256FS       0x00
+#define ADAV80X_DAC_CTRL2_INTERPOL_128FS       0x40
+#define ADAV80X_DAC_CTRL2_INTERPOL_64FS                0x80
+#define ADAV80X_DAC_CTRL2_INTERPOL_MASK                0xc0
+
+#define ADAV80X_DAC_CTRL2_DEEMPH_NONE          0x00
+#define ADAV80X_DAC_CTRL2_DEEMPH_44            0x01
+#define ADAV80X_DAC_CTRL2_DEEMPH_32            0x02
+#define ADAV80X_DAC_CTRL2_DEEMPH_48            0x03
+#define ADAV80X_DAC_CTRL2_DEEMPH_MASK          0x01
+
+#define ADAV80X_CAPTURE_MODE_MASTER            0x20
+#define ADAV80X_CAPTURE_WORD_LEN24             0x00
+#define ADAV80X_CAPTURE_WORD_LEN20             0x04
+#define ADAV80X_CAPTRUE_WORD_LEN18             0x08
+#define ADAV80X_CAPTURE_WORD_LEN16             0x0c
+#define ADAV80X_CAPTURE_WORD_LEN_MASK          0x0c
+
+#define ADAV80X_CAPTURE_MODE_LEFT_J            0x00
+#define ADAV80X_CAPTURE_MODE_I2S               0x01
+#define ADAV80X_CAPTURE_MODE_RIGHT_J           0x03
+#define ADAV80X_CAPTURE_MODE_MASK              0x03
+
+#define ADAV80X_PLAYBACK_MODE_MASTER           0x10
+#define ADAV80X_PLAYBACK_MODE_LEFT_J           0x00
+#define ADAV80X_PLAYBACK_MODE_I2S              0x01
+#define ADAV80X_PLAYBACK_MODE_RIGHT_J_24       0x04
+#define ADAV80X_PLAYBACK_MODE_RIGHT_J_20       0x05
+#define ADAV80X_PLAYBACK_MODE_RIGHT_J_18       0x06
+#define ADAV80X_PLAYBACK_MODE_RIGHT_J_16       0x07
+#define ADAV80X_PLAYBACK_MODE_MASK             0x07
+
+#define ADAV80X_PLL_OUTE_SYSCLKPD(x)           BIT(2 - (x))
+
+static u8 adav80x_default_regs[] = {
+       0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00,
+       0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37,
+       0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b,
+       0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00,
+       0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee,
+       0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f,
+       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x52, 0x00,
+};
+
+struct adav80x {
+       enum snd_soc_control_type control_type;
+
+       enum adav80x_clk_src clk_src;
+       unsigned int sysclk;
+       enum adav80x_pll_src pll_src;
+
+       unsigned int dai_fmt[2];
+       unsigned int rate;
+       bool deemph;
+       bool sysclk_pd[3];
+};
+
+static const char *adav80x_mux_text[] = {
+       "ADC",
+       "Playback",
+       "Aux Playback",
+};
+
+static const unsigned int adav80x_mux_values[] = {
+       0, 2, 3,
+};
+
+#define ADAV80X_MUX_ENUM_DECL(name, reg, shift) \
+       SOC_VALUE_ENUM_DOUBLE_DECL(name, reg, shift, 7, \
+               ARRAY_SIZE(adav80x_mux_text), adav80x_mux_text, \
+               adav80x_mux_values)
+
+static ADAV80X_MUX_ENUM_DECL(adav80x_aux_capture_enum, ADAV80X_DPATH_CTRL1, 0);
+static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3);
+static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3);
+
+static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl =
+       SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum);
+static const struct snd_kcontrol_new adav80x_capture_mux_ctrl =
+       SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum);
+static const struct snd_kcontrol_new adav80x_dac_mux_ctrl =
+       SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum);
+
+#define ADAV80X_MUX(name, ctrl) \
+       SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1),
+       SND_SOC_DAPM_ADC("ADC", NULL, ADAV80X_ADC_CTRL1, 5, 1),
+
+       SND_SOC_DAPM_PGA("Right PGA", ADAV80X_ADC_CTRL1, 0, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Left PGA", ADAV80X_ADC_CTRL1, 1, 1, NULL, 0),
+
+       SND_SOC_DAPM_AIF_OUT("AIFOUT", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIFIN", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_AIF_OUT("AIFAUXOUT", "Aux Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIFAUXIN", "Aux Playback", 0, SND_SOC_NOPM, 0, 0),
+
+       ADAV80X_MUX("Aux Capture Select", &adav80x_aux_capture_mux_ctrl),
+       ADAV80X_MUX("Capture Select", &adav80x_capture_mux_ctrl),
+       ADAV80X_MUX("DAC Select", &adav80x_dac_mux_ctrl),
+
+       SND_SOC_DAPM_INPUT("VINR"),
+       SND_SOC_DAPM_INPUT("VINL"),
+       SND_SOC_DAPM_OUTPUT("VOUTR"),
+       SND_SOC_DAPM_OUTPUT("VOUTL"),
+
+       SND_SOC_DAPM_SUPPLY("SYSCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLL1", ADAV80X_PLL_CTRL1, 2, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLL2", ADAV80X_PLL_CTRL1, 3, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("OSC", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0),
+};
+
+static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_codec *codec = source->codec;
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+       const char *clk;
+
+       switch (adav80x->clk_src) {
+       case ADAV80X_CLK_PLL1:
+               clk = "PLL1";
+               break;
+       case ADAV80X_CLK_PLL2:
+               clk = "PLL2";
+               break;
+       case ADAV80X_CLK_XTAL:
+               clk = "OSC";
+               break;
+       default:
+               return 0;
+       }
+
+       return strcmp(source->name, clk) == 0;
+}
+
+static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_codec *codec = source->codec;
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+
+       return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL;
+}
+
+
+static const struct snd_soc_dapm_route adav80x_dapm_routes[] = {
+       { "DAC Select", "ADC", "ADC" },
+       { "DAC Select", "Playback", "AIFIN" },
+       { "DAC Select", "Aux Playback", "AIFAUXIN" },
+       { "DAC", NULL,  "DAC Select" },
+
+       { "Capture Select", "ADC", "ADC" },
+       { "Capture Select", "Playback", "AIFIN" },
+       { "Capture Select", "Aux Playback", "AIFAUXIN" },
+       { "AIFOUT", NULL,  "Capture Select" },
+
+       { "Aux Capture Select", "ADC", "ADC" },
+       { "Aux Capture Select", "Playback", "AIFIN" },
+       { "Aux Capture Select", "Aux Playback", "AIFAUXIN" },
+       { "AIFAUXOUT", NULL,  "Aux Capture Select" },
+
+       { "VOUTR",  NULL, "DAC" },
+       { "VOUTL",  NULL, "DAC" },
+
+       { "Left PGA", NULL, "VINL" },
+       { "Right PGA", NULL, "VINR" },
+       { "ADC", NULL, "Left PGA" },
+       { "ADC", NULL, "Right PGA" },
+
+       { "SYSCLK", NULL, "PLL1", adav80x_dapm_sysclk_check },
+       { "SYSCLK", NULL, "PLL2", adav80x_dapm_sysclk_check },
+       { "SYSCLK", NULL, "OSC", adav80x_dapm_sysclk_check },
+       { "PLL1", NULL, "OSC", adav80x_dapm_pll_check },
+       { "PLL2", NULL, "OSC", adav80x_dapm_pll_check },
+
+       { "ADC", NULL, "SYSCLK" },
+       { "DAC", NULL, "SYSCLK" },
+       { "AIFOUT", NULL, "SYSCLK" },
+       { "AIFAUXOUT", NULL, "SYSCLK" },
+       { "AIFIN", NULL, "SYSCLK" },
+       { "AIFAUXIN", NULL, "SYSCLK" },
+};
+
+static int adav80x_set_deemph(struct snd_soc_codec *codec)
+{
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+       unsigned int val;
+
+       if (adav80x->deemph) {
+               switch (adav80x->rate) {
+               case 32000:
+                       val = ADAV80X_DAC_CTRL2_DEEMPH_32;
+                       break;
+               case 44100:
+                       val = ADAV80X_DAC_CTRL2_DEEMPH_44;
+                       break;
+               case 48000:
+               case 64000:
+               case 88200:
+               case 96000:
+                       val = ADAV80X_DAC_CTRL2_DEEMPH_48;
+                       break;
+               default:
+                       val = ADAV80X_DAC_CTRL2_DEEMPH_NONE;
+                       break;
+               }
+       } else {
+               val = ADAV80X_DAC_CTRL2_DEEMPH_NONE;
+       }
+
+       return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2,
+               ADAV80X_DAC_CTRL2_DEEMPH_MASK, val);
+}
+
+static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+       unsigned int deemph = ucontrol->value.enumerated.item[0];
+
+       if (deemph > 1)
+               return -EINVAL;
+
+       adav80x->deemph = deemph;
+
+       return adav80x_set_deemph(codec);
+}
+
+static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = adav80x->deemph;
+       return 0;
+};
+
+static const DECLARE_TLV_DB_SCALE(adav80x_inpga_tlv, 0, 50, 0);
+static const DECLARE_TLV_DB_MINMAX(adav80x_digital_tlv, -9563, 0);
+
+static const struct snd_kcontrol_new adav80x_controls[] = {
+       SOC_DOUBLE_R_TLV("Master Playback Volume", ADAV80X_DAC_L_VOL,
+               ADAV80X_DAC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv),
+       SOC_DOUBLE_R_TLV("Master Capture Volume", ADAV80X_ADC_L_VOL,
+                       ADAV80X_ADC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv),
+
+       SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAV80X_PGA_L_VOL,
+                       ADAV80X_PGA_R_VOL, 0, 0x30, 0, adav80x_inpga_tlv),
+
+       SOC_DOUBLE("Master Playback Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 0),
+       SOC_DOUBLE("Master Capture Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1),
+
+       SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0),
+
+       SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0,
+                       adav80x_get_deemph, adav80x_put_deemph),
+};
+
+static unsigned int adav80x_port_ctrl_regs[2][2] = {
+       { ADAV80X_REC_CTRL, ADAV80X_PLAYBACK_CTRL, },
+       { ADAV80X_AUX_OUT_CTRL, ADAV80X_AUX_IN_CTRL },
+};
+
+static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+       unsigned int capture = 0x00;
+       unsigned int playback = 0x00;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               capture |= ADAV80X_CAPTURE_MODE_MASTER;
+               playback |= ADAV80X_PLAYBACK_MODE_MASTER;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               capture |= ADAV80X_CAPTURE_MODE_I2S;
+               playback |= ADAV80X_PLAYBACK_MODE_I2S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               capture |= ADAV80X_CAPTURE_MODE_LEFT_J;
+               playback |= ADAV80X_PLAYBACK_MODE_LEFT_J;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               capture |= ADAV80X_CAPTURE_MODE_RIGHT_J;
+               playback |= ADAV80X_PLAYBACK_MODE_RIGHT_J_24;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0],
+               ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER,
+               capture);
+       snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback);
+
+       adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+       return 0;
+}
+
+static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
+               unsigned int sample_rate)
+{
+       unsigned int val;
+
+       if (sample_rate <= 48000)
+               val = ADAV80X_ADC_CTRL1_MODULATOR_128FS;
+       else
+               val = ADAV80X_ADC_CTRL1_MODULATOR_64FS;
+
+       snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1,
+               ADAV80X_ADC_CTRL1_MODULATOR_MASK, val);
+
+       return 0;
+}
+
+static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
+               unsigned int sample_rate)
+{
+       unsigned int val;
+
+       if (sample_rate <= 48000)
+               val = ADAV80X_DAC_CTRL2_DIV1 | ADAV80X_DAC_CTRL2_INTERPOL_256FS;
+       else
+               val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS;
+
+       snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2,
+               ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK,
+               val);
+
+       return 0;
+}
+
+static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec,
+               struct snd_soc_dai *dai, snd_pcm_format_t format)
+{
+       unsigned int val;
+
+       switch (format) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               val = ADAV80X_CAPTURE_WORD_LEN16;
+               break;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+               val = ADAV80X_CAPTRUE_WORD_LEN18;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val = ADAV80X_CAPTURE_WORD_LEN20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val = ADAV80X_CAPTURE_WORD_LEN24;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0],
+               ADAV80X_CAPTURE_WORD_LEN_MASK, val);
+
+       return 0;
+}
+
+static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,
+               struct snd_soc_dai *dai, snd_pcm_format_t format)
+{
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+       unsigned int val;
+
+       if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J)
+               return 0;
+
+       switch (format) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16;
+               break;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+               val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1],
+               ADAV80X_PLAYBACK_MODE_MASK, val);
+
+       return 0;
+}
+
+static int adav80x_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+       unsigned int rate = params_rate(params);
+
+       if (rate * 256 != adav80x->sysclk)
+               return -EINVAL;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               adav80x_set_playback_pcm_format(codec, dai,
+                       params_format(params));
+               adav80x_set_dac_clock(codec, rate);
+       } else {
+               adav80x_set_capture_pcm_format(codec, dai,
+                       params_format(params));
+               adav80x_set_adc_clock(codec, rate);
+       }
+       adav80x->rate = rate;
+       adav80x_set_deemph(codec);
+
+       return 0;
+}
+
+static int adav80x_set_sysclk(struct snd_soc_codec *codec,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+
+       if (dir == SND_SOC_CLOCK_IN) {
+               switch (clk_id) {
+               case ADAV80X_CLK_XIN:
+               case ADAV80X_CLK_XTAL:
+               case ADAV80X_CLK_MCLKI:
+               case ADAV80X_CLK_PLL1:
+               case ADAV80X_CLK_PLL2:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               adav80x->sysclk = freq;
+
+               if (adav80x->clk_src != clk_id) {
+                       unsigned int iclk_ctrl1, iclk_ctrl2;
+
+                       adav80x->clk_src = clk_id;
+                       if (clk_id == ADAV80X_CLK_XTAL)
+                               clk_id = ADAV80X_CLK_XIN;
+
+                       iclk_ctrl1 = ADAV80X_ICLK_CTRL1_DAC_SRC(clk_id) |
+                                       ADAV80X_ICLK_CTRL1_ADC_SRC(clk_id) |
+                                       ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id);
+                       iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id);
+
+                       snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1);
+                       snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2);
+
+                       snd_soc_dapm_sync(&codec->dapm);
+               }
+       } else {
+               unsigned int mask;
+
+               switch (clk_id) {
+               case ADAV80X_CLK_SYSCLK1:
+               case ADAV80X_CLK_SYSCLK2:
+               case ADAV80X_CLK_SYSCLK3:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               clk_id -= ADAV80X_CLK_SYSCLK1;
+               mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id);
+
+               if (freq == 0) {
+                       snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask);
+                       adav80x->sysclk_pd[clk_id] = true;
+               } else {
+                       snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0);
+                       adav80x->sysclk_pd[clk_id] = false;
+               }
+
+               if (adav80x->sysclk_pd[0])
+                       snd_soc_dapm_disable_pin(&codec->dapm, "PLL1");
+               else
+                       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
+
+               if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2])
+                       snd_soc_dapm_disable_pin(&codec->dapm, "PLL2");
+               else
+                       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
+
+               snd_soc_dapm_sync(&codec->dapm);
+       }
+
+       return 0;
+}
+
+static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
+{
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+       unsigned int pll_ctrl1 = 0;
+       unsigned int pll_ctrl2 = 0;
+       unsigned int pll_src;
+
+       switch (source) {
+       case ADAV80X_PLL_SRC_XTAL:
+       case ADAV80X_PLL_SRC_XIN:
+       case ADAV80X_PLL_SRC_MCLKI:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!freq_out)
+               return 0;
+
+       switch (freq_in) {
+       case 27000000:
+               break;
+       case 54000000:
+               if (source == ADAV80X_PLL_SRC_XIN) {
+                       pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV;
+                       break;
+               }
+       default:
+               return -EINVAL;
+       }
+
+       if (freq_out > 12288000) {
+               pll_ctrl2 |= ADAV80X_PLL_CTRL2_DOUB(pll_id);
+               freq_out /= 2;
+       }
+
+       /* freq_out = sample_rate * 256 */
+       switch (freq_out) {
+       case 8192000:
+               pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_32(pll_id);
+               break;
+       case 11289600:
+               pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_44(pll_id);
+               break;
+       case 12288000:
+               pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_48(pll_id);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV,
+               pll_ctrl1);
+       snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2,
+                       ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2);
+
+       if (source != adav80x->pll_src) {
+               if (source == ADAV80X_PLL_SRC_MCLKI)
+                       pll_src = ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll_id);
+               else
+                       pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id);
+
+               snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC,
+                               ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src);
+
+               adav80x->pll_src = source;
+
+               snd_soc_dapm_sync(&codec->dapm);
+       }
+
+       return 0;
+}
+
+static int adav80x_set_bias_level(struct snd_soc_codec *codec,
+               enum snd_soc_bias_level level)
+{
+       unsigned int mask = ADAV80X_DAC_CTRL1_PD;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00);
+               break;
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+/* Enforce the same sample rate on all audio interfaces */
+static int adav80x_dai_startup(struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+
+       if (!codec->active || !adav80x->rate)
+               return 0;
+
+       return snd_pcm_hw_constraint_minmax(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_RATE, adav80x->rate, adav80x->rate);
+}
+
+static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+
+       if (!codec->active)
+               adav80x->rate = 0;
+}
+
+static const struct snd_soc_dai_ops adav80x_dai_ops = {
+       .set_fmt = adav80x_set_dai_fmt,
+       .hw_params = adav80x_hw_params,
+       .startup = adav80x_dai_startup,
+       .shutdown = adav80x_dai_shutdown,
+};
+
+#define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | \
+       SNDRV_PCM_RATE_96000)
+
+#define ADAV80X_CAPTURE_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+
+#define ADAV80X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver adav80x_dais[] = {
+       {
+               .name = "adav80x-hifi",
+               .id = 0,
+               .playback = {
+                       .stream_name = "HiFi Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = ADAV80X_PLAYBACK_RATES,
+                       .formats = ADAV80X_FORMATS,
+       },
+               .capture = {
+                       .stream_name = "HiFi Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = ADAV80X_CAPTURE_RATES,
+                       .formats = ADAV80X_FORMATS,
+               },
+               .ops = &adav80x_dai_ops,
+       },
+       {
+               .name = "adav80x-aux",
+               .id = 1,
+               .playback = {
+                       .stream_name = "Aux Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = ADAV80X_PLAYBACK_RATES,
+                       .formats = ADAV80X_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Aux Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = ADAV80X_CAPTURE_RATES,
+                       .formats = ADAV80X_FORMATS,
+               },
+               .ops = &adav80x_dai_ops,
+       },
+};
+
+static int adav80x_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type);
+       if (ret) {
+               dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       /* Force PLLs on for SYSCLK output */
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
+
+       /* Power down S/PDIF receiver, since it is currently not supported */
+       snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20);
+       /* Disable DAC zero flag */
+       snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6);
+
+       return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+}
+
+static int adav80x_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int adav80x_resume(struct snd_soc_codec *codec)
+{
+       adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       codec->cache_sync = 1;
+       snd_soc_cache_sync(codec);
+
+       return 0;
+}
+
+static int adav80x_remove(struct snd_soc_codec *codec)
+{
+       return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static struct snd_soc_codec_driver adav80x_codec_driver = {
+       .probe = adav80x_probe,
+       .remove = adav80x_remove,
+       .suspend = adav80x_suspend,
+       .resume = adav80x_resume,
+       .set_bias_level = adav80x_set_bias_level,
+
+       .set_pll = adav80x_set_pll,
+       .set_sysclk = adav80x_set_sysclk,
+
+       .reg_word_size = sizeof(u8),
+       .reg_cache_size = ARRAY_SIZE(adav80x_default_regs),
+       .reg_cache_default = adav80x_default_regs,
+
+       .controls = adav80x_controls,
+       .num_controls = ARRAY_SIZE(adav80x_controls),
+       .dapm_widgets = adav80x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets),
+       .dapm_routes = adav80x_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes),
+};
+
+static int __devinit adav80x_bus_probe(struct device *dev,
+               enum snd_soc_control_type control_type)
+{
+       struct adav80x *adav80x;
+       int ret;
+
+       adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL);
+       if (!adav80x)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, adav80x);
+       adav80x->control_type = control_type;
+
+       ret = snd_soc_register_codec(dev, &adav80x_codec_driver,
+               adav80x_dais, ARRAY_SIZE(adav80x_dais));
+       if (ret)
+               kfree(adav80x);
+
+       return ret;
+}
+
+static int __devexit adav80x_bus_remove(struct device *dev)
+{
+       snd_soc_unregister_codec(dev);
+       kfree(dev_get_drvdata(dev));
+       return 0;
+}
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit adav80x_spi_probe(struct spi_device *spi)
+{
+       return adav80x_bus_probe(&spi->dev, SND_SOC_SPI);
+}
+
+static int __devexit adav80x_spi_remove(struct spi_device *spi)
+{
+       return adav80x_bus_remove(&spi->dev);
+}
+
+static struct spi_driver adav80x_spi_driver = {
+       .driver = {
+               .name   = "adav801",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = adav80x_spi_probe,
+       .remove         = __devexit_p(adav80x_spi_remove),
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static const struct i2c_device_id adav80x_id[] = {
+       { "adav803", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adav80x_id);
+
+static int __devinit adav80x_i2c_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       return adav80x_bus_probe(&client->dev, SND_SOC_I2C);
+}
+
+static int __devexit adav80x_i2c_remove(struct i2c_client *client)
+{
+       return adav80x_bus_remove(&client->dev);
+}
+
+static struct i2c_driver adav80x_i2c_driver = {
+       .driver = {
+               .name = "adav803",
+               .owner = THIS_MODULE,
+       },
+       .probe = adav80x_i2c_probe,
+       .remove = __devexit_p(adav80x_i2c_remove),
+       .id_table = adav80x_id,
+};
+#endif
+
+static int __init adav80x_init(void)
+{
+       int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&adav80x_i2c_driver);
+       if (ret)
+               return ret;
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&adav80x_spi_driver);
+#endif
+
+       return ret;
+}
+module_init(adav80x_init);
+
+static void __exit adav80x_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&adav80x_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&adav80x_spi_driver);
+#endif
+}
+module_exit(adav80x_exit);
+
+MODULE_DESCRIPTION("ASoC ADAV80x driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adav80x.h b/sound/soc/codecs/adav80x.h
new file mode 100644 (file)
index 0000000..adb0fc7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * header file for ADAV80X parts
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADAV80X_H
+#define _ADAV80X_H
+
+enum adav80x_pll_src {
+       ADAV80X_PLL_SRC_XIN,
+       ADAV80X_PLL_SRC_XTAL,
+       ADAV80X_PLL_SRC_MCLKI,
+};
+
+enum adav80x_pll {
+       ADAV80X_PLL1 = 0,
+       ADAV80X_PLL2 = 1,
+};
+
+enum adav80x_clk_src {
+       ADAV80X_CLK_XIN = 0,
+       ADAV80X_CLK_MCLKI = 1,
+       ADAV80X_CLK_PLL1 = 2,
+       ADAV80X_CLK_PLL2 = 3,
+       ADAV80X_CLK_XTAL = 6,
+
+       ADAV80X_CLK_SYSCLK1 = 6,
+       ADAV80X_CLK_SYSCLK2 = 7,
+       ADAV80X_CLK_SYSCLK3 = 8,
+};
+
+#endif
index ed96f24..7a64e58 100644 (file)
@@ -457,7 +457,7 @@ static struct snd_soc_dai_ops ak4641_pcm_dai_ops = {
        .set_sysclk   = ak4641_set_dai_sysclk,
 };
 
-struct snd_soc_dai_driver ak4641_dai[] = {
+static struct snd_soc_dai_driver ak4641_dai[] = {
 {
        .name = "ak4641-hifi",
        .id = 1,
index 0206a17..6cc8678 100644 (file)
@@ -636,10 +636,7 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)
 #endif /* CONFIG_PM */
 
 /*
- * ASoC codec device structure
- *
- * Assign this variable to the codec_dev field of the machine driver's
- * snd_soc_device structure.
+ * ASoC codec driver structure
  */
 static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
        .probe =                cs4270_probe,
index 4173b67..ac65a2d 100644 (file)
@@ -1397,8 +1397,6 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
        if (freq == max98088->sysclk)
                return 0;
 
-       max98088->sysclk = freq; /* remember current sysclk */
-
        /* Setup clocks for slave mode, and using the PLL
         * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
         *         0x02 (when master clk is 20MHz to 30MHz)..
index e1d282d..668434d 100644 (file)
@@ -1517,8 +1517,6 @@ static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
        if (freq == max98095->sysclk)
                return 0;
 
-       max98095->sysclk = freq; /* remember current sysclk */
-
        /* Setup clocks for slave mode, and using the PLL
         * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
         *         0x02 (when master clk is 20MHz to 40MHz)..
@@ -2261,11 +2259,11 @@ static int max98095_probe(struct snd_soc_codec *codec)
 
        ret = snd_soc_read(codec, M98095_0FF_REV_ID);
        if (ret < 0) {
-               dev_err(codec->dev, "Failed to read device revision: %d\n",
+               dev_err(codec->dev, "Failure reading hardware revision: %d\n",
                        ret);
                goto err_access;
        }
-       dev_info(codec->dev, "revision %c\n", ret + 'A');
+       dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A');
 
        snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV);
 
@@ -2342,8 +2340,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
        max98095->control_data = i2c;
        max98095->pdata = i2c->dev.platform_data;
 
-       ret = snd_soc_register_codec(&i2c->dev,
-                       &soc_codec_dev_max98095, &max98095_dai[0], 3);
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98095,
+                                    max98095_dai, ARRAY_SIZE(max98095_dai));
        if (ret < 0)
                kfree(max98095);
        return ret;
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
new file mode 100644 (file)
index 0000000..409d89d
--- /dev/null
@@ -0,0 +1,917 @@
+/*
+ * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Johannes Stezenbach <js@sig21.net>
+ *
+ * based on code from:
+ *     Wolfson Microelectronics PLC.
+ *       Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *     Freescale Semiconductor, Inc.
+ *       Timur Tabi <timur@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "sta32x.h"
+
+#define STA32X_RATES (SNDRV_PCM_RATE_32000 | \
+                     SNDRV_PCM_RATE_44100 | \
+                     SNDRV_PCM_RATE_48000 | \
+                     SNDRV_PCM_RATE_88200 | \
+                     SNDRV_PCM_RATE_96000 | \
+                     SNDRV_PCM_RATE_176400 | \
+                     SNDRV_PCM_RATE_192000)
+
+#define STA32X_FORMATS \
+       (SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+        SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+        SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE  | \
+        SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE)
+
+/* Power-up register defaults */
+static const u8 sta32x_regs[STA32X_REGISTER_COUNT] = {
+       0x63, 0x80, 0xc2, 0x40, 0xc2, 0x5c, 0x10, 0xff, 0x60, 0x60,
+       0x60, 0x80, 0x00, 0x00, 0x00, 0x40, 0x80, 0x77, 0x6a, 0x69,
+       0x6a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
+       0xc0, 0xf3, 0x33, 0x00, 0x0c,
+};
+
+/* regulator power supply names */
+static const char *sta32x_supply_names[] = {
+       "Vdda", /* analog supply, 3.3VV */
+       "Vdd3", /* digital supply, 3.3V */
+       "Vcc"   /* power amp spply, 10V - 36V */
+};
+
+/* codec private data */
+struct sta32x_priv {
+       struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
+       struct snd_soc_codec *codec;
+
+       unsigned int mclk;
+       unsigned int format;
+};
+
+static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0);
+
+static const char *sta32x_drc_ac[] = {
+       "Anti-Clipping", "Dynamic Range Compression" };
+static const char *sta32x_auto_eq_mode[] = {
+       "User", "Preset", "Loudness" };
+static const char *sta32x_auto_gc_mode[] = {
+       "User", "AC no clipping", "AC limited clipping (10%)",
+       "DRC nighttime listening mode" };
+static const char *sta32x_auto_xo_mode[] = {
+       "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz",
+       "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" };
+static const char *sta32x_preset_eq_mode[] = {
+       "Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft",
+       "Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1",
+       "Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2",
+       "Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7",
+       "Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12",
+       "Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" };
+static const char *sta32x_limiter_select[] = {
+       "Limiter Disabled", "Limiter #1", "Limiter #2" };
+static const char *sta32x_limiter_attack_rate[] = {
+       "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024",
+       "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752",
+       "0.0645", "0.0564", "0.0501", "0.0451" };
+static const char *sta32x_limiter_release_rate[] = {
+       "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
+       "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
+       "0.0134", "0.0117", "0.0110", "0.0104" };
+
+static const unsigned int sta32x_limiter_ac_attack_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+       8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
+};
+
+static const unsigned int sta32x_limiter_ac_release_tlv[] = {
+       TLV_DB_RANGE_HEAD(5),
+       0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
+       3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
+       8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
+};
+
+static const unsigned int sta32x_limiter_drc_attack_tlv[] = {
+       TLV_DB_RANGE_HEAD(3),
+       0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
+       8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
+       14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
+};
+
+static const unsigned int sta32x_limiter_drc_release_tlv[] = {
+       TLV_DB_RANGE_HEAD(5),
+       0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+       1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
+       3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
+       5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
+       13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
+};
+
+static const struct soc_enum sta32x_drc_ac_enum =
+       SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
+                       2, sta32x_drc_ac);
+static const struct soc_enum sta32x_auto_eq_enum =
+       SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
+                       3, sta32x_auto_eq_mode);
+static const struct soc_enum sta32x_auto_gc_enum =
+       SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
+                       4, sta32x_auto_gc_mode);
+static const struct soc_enum sta32x_auto_xo_enum =
+       SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
+                       16, sta32x_auto_xo_mode);
+static const struct soc_enum sta32x_preset_eq_enum =
+       SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
+                       32, sta32x_preset_eq_mode);
+static const struct soc_enum sta32x_limiter_ch1_enum =
+       SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
+                       3, sta32x_limiter_select);
+static const struct soc_enum sta32x_limiter_ch2_enum =
+       SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
+                       3, sta32x_limiter_select);
+static const struct soc_enum sta32x_limiter_ch3_enum =
+       SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
+                       3, sta32x_limiter_select);
+static const struct soc_enum sta32x_limiter1_attack_rate_enum =
+       SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT,
+                       16, sta32x_limiter_attack_rate);
+static const struct soc_enum sta32x_limiter2_attack_rate_enum =
+       SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT,
+                       16, sta32x_limiter_attack_rate);
+static const struct soc_enum sta32x_limiter1_release_rate_enum =
+       SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT,
+                       16, sta32x_limiter_release_rate);
+static const struct soc_enum sta32x_limiter2_release_rate_enum =
+       SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT,
+                       16, sta32x_limiter_release_rate);
+
+/* byte array controls for setting biquad, mixer, scaling coefficients;
+ * for biquads all five coefficients need to be set in one go,
+ * mixer and pre/postscale coefs can be set individually;
+ * each coef is 24bit, the bytes are ordered in the same way
+ * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0)
+ */
+
+static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       int numcoef = kcontrol->private_value >> 16;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = 3 * numcoef;
+       return 0;
+}
+
+static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int numcoef = kcontrol->private_value >> 16;
+       int index = kcontrol->private_value & 0xffff;
+       unsigned int cfud;
+       int i;
+
+       /* preserve reserved bits in STA32X_CFUD */
+       cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
+       /* chip documentation does not say if the bits are self clearing,
+        * so do it explicitly */
+       snd_soc_write(codec, STA32X_CFUD, cfud);
+
+       snd_soc_write(codec, STA32X_CFADDR2, index);
+       if (numcoef == 1)
+               snd_soc_write(codec, STA32X_CFUD, cfud | 0x04);
+       else if (numcoef == 5)
+               snd_soc_write(codec, STA32X_CFUD, cfud | 0x08);
+       else
+               return -EINVAL;
+       for (i = 0; i < 3 * numcoef; i++)
+               ucontrol->value.bytes.data[i] =
+                       snd_soc_read(codec, STA32X_B1CF1 + i);
+
+       return 0;
+}
+
+static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int numcoef = kcontrol->private_value >> 16;
+       int index = kcontrol->private_value & 0xffff;
+       unsigned int cfud;
+       int i;
+
+       /* preserve reserved bits in STA32X_CFUD */
+       cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
+       /* chip documentation does not say if the bits are self clearing,
+        * so do it explicitly */
+       snd_soc_write(codec, STA32X_CFUD, cfud);
+
+       snd_soc_write(codec, STA32X_CFADDR2, index);
+       for (i = 0; i < 3 * numcoef; i++)
+               snd_soc_write(codec, STA32X_B1CF1 + i,
+                             ucontrol->value.bytes.data[i]);
+       if (numcoef == 1)
+               snd_soc_write(codec, STA32X_CFUD, cfud | 0x01);
+       else if (numcoef == 5)
+               snd_soc_write(codec, STA32X_CFUD, cfud | 0x02);
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+#define SINGLE_COEF(xname, index) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = sta32x_coefficient_info, \
+       .get = sta32x_coefficient_get,\
+       .put = sta32x_coefficient_put, \
+       .private_value = index | (1 << 16) }
+
+#define BIQUAD_COEFS(xname, index) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = sta32x_coefficient_info, \
+       .get = sta32x_coefficient_get,\
+       .put = sta32x_coefficient_put, \
+       .private_value = index | (5 << 16) }
+
+static const struct snd_kcontrol_new sta32x_snd_controls[] = {
+SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv),
+SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1),
+SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1),
+SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1),
+SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1),
+SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0),
+SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum),
+SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0),
+SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0),
+SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0),
+SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0),
+SOC_ENUM("Automode EQ", sta32x_auto_eq_enum),
+SOC_ENUM("Automode GC", sta32x_auto_gc_enum),
+SOC_ENUM("Automode XO", sta32x_auto_xo_enum),
+SOC_ENUM("Preset EQ", sta32x_preset_eq_enum),
+SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
+SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum),
+SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum),
+SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum),
+SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv),
+SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv),
+SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
+SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
+SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
+SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
+
+/* depending on mode, the attack/release thresholds have
+ * two different enum definitions; provide both
+ */
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
+              16, 0, sta32x_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
+              16, 0, sta32x_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
+              16, 0, sta32x_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
+              16, 0, sta32x_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
+              16, 0, sta32x_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
+              16, 0, sta32x_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
+              16, 0, sta32x_limiter_drc_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
+              16, 0, sta32x_limiter_drc_release_tlv),
+
+BIQUAD_COEFS("Ch1 - Biquad 1", 0),
+BIQUAD_COEFS("Ch1 - Biquad 2", 5),
+BIQUAD_COEFS("Ch1 - Biquad 3", 10),
+BIQUAD_COEFS("Ch1 - Biquad 4", 15),
+BIQUAD_COEFS("Ch2 - Biquad 1", 20),
+BIQUAD_COEFS("Ch2 - Biquad 2", 25),
+BIQUAD_COEFS("Ch2 - Biquad 3", 30),
+BIQUAD_COEFS("Ch2 - Biquad 4", 35),
+BIQUAD_COEFS("High-pass", 40),
+BIQUAD_COEFS("Low-pass", 45),
+SINGLE_COEF("Ch1 - Prescale", 50),
+SINGLE_COEF("Ch2 - Prescale", 51),
+SINGLE_COEF("Ch1 - Postscale", 52),
+SINGLE_COEF("Ch2 - Postscale", 53),
+SINGLE_COEF("Ch3 - Postscale", 54),
+SINGLE_COEF("Thermal warning - Postscale", 55),
+SINGLE_COEF("Ch1 - Mix 1", 56),
+SINGLE_COEF("Ch1 - Mix 2", 57),
+SINGLE_COEF("Ch2 - Mix 1", 58),
+SINGLE_COEF("Ch2 - Mix 2", 59),
+SINGLE_COEF("Ch3 - Mix 1", 60),
+SINGLE_COEF("Ch3 - Mix 2", 61),
+};
+
+static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("LEFT"),
+SND_SOC_DAPM_OUTPUT("RIGHT"),
+SND_SOC_DAPM_OUTPUT("SUB"),
+};
+
+static const struct snd_soc_dapm_route sta32x_dapm_routes[] = {
+       { "LEFT", NULL, "DAC" },
+       { "RIGHT", NULL, "DAC" },
+       { "SUB", NULL, "DAC" },
+};
+
+/* MCLK interpolation ratio per fs */
+static struct {
+       int fs;
+       int ir;
+} interpolation_ratios[] = {
+       { 32000, 0 },
+       { 44100, 0 },
+       { 48000, 0 },
+       { 88200, 1 },
+       { 96000, 1 },
+       { 176400, 2 },
+       { 192000, 2 },
+};
+
+/* MCLK to fs clock ratios */
+static struct {
+       int ratio;
+       int mcs;
+} mclk_ratios[3][7] = {
+       { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 },
+         { 128, 4 }, { 576, 5 }, { 0, 0 } },
+       { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
+       { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
+};
+
+
+/**
+ * sta32x_set_dai_sysclk - configure MCLK
+ * @codec_dai: the codec DAI
+ * @clk_id: the clock ID (ignored)
+ * @freq: the MCLK input frequency
+ * @dir: the clock direction (ignored)
+ *
+ * The value of MCLK is used to determine which sample rates are supported
+ * by the STA32X, based on the mclk_ratios table.
+ *
+ * This function must be called by the machine driver's 'startup' function,
+ * otherwise the list of supported sample rates will not be available in
+ * time for ALSA.
+ *
+ * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
+ * theoretically possible sample rates to be enabled. Call it again with a
+ * proper value set one the external clock is set (most probably you would do
+ * that from a machine's driver 'hw_param' hook.
+ */
+static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+       int i, j, ir, fs;
+       unsigned int rates = 0;
+       unsigned int rate_min = -1;
+       unsigned int rate_max = 0;
+
+       pr_debug("mclk=%u\n", freq);
+       sta32x->mclk = freq;
+
+       if (sta32x->mclk) {
+               for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
+                       ir = interpolation_ratios[i].ir;
+                       fs = interpolation_ratios[i].fs;
+                       for (j = 0; mclk_ratios[ir][j].ratio; j++) {
+                               if (mclk_ratios[ir][j].ratio * fs == freq) {
+                                       rates |= snd_pcm_rate_to_rate_bit(fs);
+                                       if (fs < rate_min)
+                                               rate_min = fs;
+                                       if (fs > rate_max)
+                                               rate_max = fs;
+                               }
+                       }
+               }
+               /* FIXME: soc should support a rate list */
+               rates &= ~SNDRV_PCM_RATE_KNOT;
+
+               if (!rates) {
+                       dev_err(codec->dev, "could not find a valid sample rate\n");
+                       return -EINVAL;
+               }
+       } else {
+               /* enable all possible rates */
+               rates = STA32X_RATES;
+               rate_min = 32000;
+               rate_max = 192000;
+       }
+
+       codec_dai->driver->playback.rates = rates;
+       codec_dai->driver->playback.rate_min = rate_min;
+       codec_dai->driver->playback.rate_max = rate_max;
+       return 0;
+}
+
+/**
+ * sta32x_set_dai_fmt - configure the codec for the selected audio format
+ * @codec_dai: the codec DAI
+ * @fmt: a SND_SOC_DAIFMT_x value indicating the data format
+ *
+ * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
+ * codec accordingly.
+ */
+static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+       u8 confb = snd_soc_read(codec, STA32X_CONFB);
+
+       pr_debug("\n");
+       confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               confb |= STA32X_CONFB_C2IM;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               confb |= STA32X_CONFB_C1IM;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, STA32X_CONFB, confb);
+       return 0;
+}
+
+/**
+ * sta32x_hw_params - program the STA32X with the given hardware parameters.
+ * @substream: the audio stream
+ * @params: the hardware parameters to set
+ * @dai: the SOC DAI (ignored)
+ *
+ * This function programs the hardware with the values provided.
+ * Specifically, the sample rate and the data format.
+ */
+static int sta32x_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+       unsigned int rate;
+       int i, mcs = -1, ir = -1;
+       u8 confa, confb;
+
+       rate = params_rate(params);
+       pr_debug("rate: %u\n", rate);
+       for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++)
+               if (interpolation_ratios[i].fs == rate)
+                       ir = interpolation_ratios[i].ir;
+       if (ir < 0)
+               return -EINVAL;
+       for (i = 0; mclk_ratios[ir][i].ratio; i++)
+               if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk)
+                       mcs = mclk_ratios[ir][i].mcs;
+       if (mcs < 0)
+               return -EINVAL;
+
+       confa = snd_soc_read(codec, STA32X_CONFA);
+       confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK);
+       confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT);
+
+       confb = snd_soc_read(codec, STA32X_CONFB);
+       confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB);
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S24_LE:
+       case SNDRV_PCM_FORMAT_S24_BE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
+       case SNDRV_PCM_FORMAT_S24_3BE:
+               pr_debug("24bit\n");
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S32_LE:
+       case SNDRV_PCM_FORMAT_S32_BE:
+               pr_debug("24bit or 32bit\n");
+               switch (sta32x->format) {
+               case SND_SOC_DAIFMT_I2S:
+                       confb |= 0x0;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       confb |= 0x1;
+                       break;
+               case SND_SOC_DAIFMT_RIGHT_J:
+                       confb |= 0x2;
+                       break;
+               }
+
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+       case SNDRV_PCM_FORMAT_S20_3BE:
+               pr_debug("20bit\n");
+               switch (sta32x->format) {
+               case SND_SOC_DAIFMT_I2S:
+                       confb |= 0x4;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       confb |= 0x5;
+                       break;
+               case SND_SOC_DAIFMT_RIGHT_J:
+                       confb |= 0x6;
+                       break;
+               }
+
+               break;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+       case SNDRV_PCM_FORMAT_S18_3BE:
+               pr_debug("18bit\n");
+               switch (sta32x->format) {
+               case SND_SOC_DAIFMT_I2S:
+                       confb |= 0x8;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       confb |= 0x9;
+                       break;
+               case SND_SOC_DAIFMT_RIGHT_J:
+                       confb |= 0xa;
+                       break;
+               }
+
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+       case SNDRV_PCM_FORMAT_S16_BE:
+               pr_debug("16bit\n");
+               switch (sta32x->format) {
+               case SND_SOC_DAIFMT_I2S:
+                       confb |= 0x0;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       confb |= 0xd;
+                       break;
+               case SND_SOC_DAIFMT_RIGHT_J:
+                       confb |= 0xe;
+                       break;
+               }
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, STA32X_CONFA, confa);
+       snd_soc_write(codec, STA32X_CONFB, confb);
+       return 0;
+}
+
+/**
+ * sta32x_set_bias_level - DAPM callback
+ * @codec: the codec device
+ * @level: DAPM power level
+ *
+ * This is called by ALSA to put the codec into low power mode
+ * or to wake it up.  If the codec is powered off completely
+ * all registers must be restored after power on.
+ */
+static int sta32x_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       int ret;
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+
+       pr_debug("level = %d\n", level);
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* Full power on */
+               snd_soc_update_bits(codec, STA32X_CONFF,
+                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
+                                                   sta32x->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n", ret);
+                               return ret;
+                       }
+
+                       snd_soc_cache_sync(codec);
+               }
+
+               /* Power up to mute */
+               /* FIXME */
+               snd_soc_update_bits(codec, STA32X_CONFF,
+                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
+
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* The chip runs through the power down sequence for us. */
+               snd_soc_update_bits(codec, STA32X_CONFF,
+                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+                                   STA32X_CONFF_PWDN);
+               msleep(300);
+
+               regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
+                                      sta32x->supplies);
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+static struct snd_soc_dai_ops sta32x_dai_ops = {
+       .hw_params      = sta32x_hw_params,
+       .set_sysclk     = sta32x_set_dai_sysclk,
+       .set_fmt        = sta32x_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver sta32x_dai = {
+       .name = "STA32X",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = STA32X_RATES,
+               .formats = STA32X_FORMATS,
+       },
+       .ops = &sta32x_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int sta32x_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int sta32x_resume(struct snd_soc_codec *codec)
+{
+       sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define sta32x_suspend NULL
+#define sta32x_resume NULL
+#endif
+
+static int sta32x_probe(struct snd_soc_codec *codec)
+{
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+       int i, ret = 0;
+
+       sta32x->codec = codec;
+
+       /* regulators */
+       for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
+               sta32x->supplies[i].supply = sta32x_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sta32x->supplies),
+                                sta32x->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
+                                   sta32x->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       /* Tell ASoC what kind of I/O to use to read the registers.  ASoC will
+        * then do the I2C transactions itself.
+        */
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
+               return ret;
+       }
+
+       /* read reg reset values into cache */
+       for (i = 0; i < STA32X_REGISTER_COUNT; i++)
+               snd_soc_cache_write(codec, i, sta32x_regs[i]);
+
+       /* preserve reset values of reserved register bits */
+       snd_soc_cache_write(codec, STA32X_CONFC,
+                           codec->hw_read(codec, STA32X_CONFC));
+       snd_soc_cache_write(codec, STA32X_CONFE,
+                           codec->hw_read(codec, STA32X_CONFE));
+       snd_soc_cache_write(codec, STA32X_CONFF,
+                           codec->hw_read(codec, STA32X_CONFF));
+       snd_soc_cache_write(codec, STA32X_MMUTE,
+                           codec->hw_read(codec, STA32X_MMUTE));
+       snd_soc_cache_write(codec, STA32X_AUTO1,
+                           codec->hw_read(codec, STA32X_AUTO1));
+       snd_soc_cache_write(codec, STA32X_AUTO3,
+                           codec->hw_read(codec, STA32X_AUTO3));
+       snd_soc_cache_write(codec, STA32X_C3CFG,
+                           codec->hw_read(codec, STA32X_C3CFG));
+
+       /* FIXME enable thermal warning adjustment and recovery  */
+       snd_soc_update_bits(codec, STA32X_CONFA,
+                           STA32X_CONFA_TWAB | STA32X_CONFA_TWRB, 0);
+
+       /* FIXME select 2.1 mode  */
+       snd_soc_update_bits(codec, STA32X_CONFF,
+                           STA32X_CONFF_OCFG_MASK,
+                           1 << STA32X_CONFF_OCFG_SHIFT);
+
+       /* FIXME channel to output mapping */
+       snd_soc_update_bits(codec, STA32X_C1CFG,
+                           STA32X_CxCFG_OM_MASK,
+                           0 << STA32X_CxCFG_OM_SHIFT);
+       snd_soc_update_bits(codec, STA32X_C2CFG,
+                           STA32X_CxCFG_OM_MASK,
+                           1 << STA32X_CxCFG_OM_SHIFT);
+       snd_soc_update_bits(codec, STA32X_C3CFG,
+                           STA32X_CxCFG_OM_MASK,
+                           2 << STA32X_CxCFG_OM_SHIFT);
+
+       sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       /* Bias level configuration will have done an extra enable */
+       regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
+
+       return 0;
+
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
+err:
+       return ret;
+}
+
+static int sta32x_remove(struct snd_soc_codec *codec)
+{
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+
+       regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
+       regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
+
+       return 0;
+}
+
+static int sta32x_reg_is_volatile(struct snd_soc_codec *codec,
+                                 unsigned int reg)
+{
+       switch (reg) {
+       case STA32X_CONFA ... STA32X_L2ATRT:
+       case STA32X_MPCC1 ... STA32X_FDRC2:
+               return 0;
+       }
+       return 1;
+}
+
+static const struct snd_soc_codec_driver sta32x_codec = {
+       .probe =                sta32x_probe,
+       .remove =               sta32x_remove,
+       .suspend =              sta32x_suspend,
+       .resume =               sta32x_resume,
+       .reg_cache_size =       STA32X_REGISTER_COUNT,
+       .reg_word_size =        sizeof(u8),
+       .volatile_register =    sta32x_reg_is_volatile,
+       .set_bias_level =       sta32x_set_bias_level,
+       .controls =             sta32x_snd_controls,
+       .num_controls =         ARRAY_SIZE(sta32x_snd_controls),
+       .dapm_widgets =         sta32x_dapm_widgets,
+       .num_dapm_widgets =     ARRAY_SIZE(sta32x_dapm_widgets),
+       .dapm_routes =          sta32x_dapm_routes,
+       .num_dapm_routes =      ARRAY_SIZE(sta32x_dapm_routes),
+};
+
+static __devinit int sta32x_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct sta32x_priv *sta32x;
+       int ret;
+
+       sta32x = kzalloc(sizeof(struct sta32x_priv), GFP_KERNEL);
+       if (!sta32x)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, sta32x);
+
+       ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static __devexit int sta32x_i2c_remove(struct i2c_client *client)
+{
+       struct sta32x_priv *sta32x = i2c_get_clientdata(client);
+       struct snd_soc_codec *codec = sta32x->codec;
+
+       if (codec)
+               sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
+
+       if (codec) {
+               snd_soc_unregister_codec(&client->dev);
+               snd_soc_codec_set_drvdata(codec, NULL);
+       }
+
+       kfree(sta32x);
+       return 0;
+}
+
+static const struct i2c_device_id sta32x_i2c_id[] = {
+       { "sta326", 0 },
+       { "sta328", 0 },
+       { "sta329", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id);
+
+static struct i2c_driver sta32x_i2c_driver = {
+       .driver = {
+               .name = "sta32x",
+               .owner = THIS_MODULE,
+       },
+       .probe =    sta32x_i2c_probe,
+       .remove =   __devexit_p(sta32x_i2c_remove),
+       .id_table = sta32x_i2c_id,
+};
+
+static int __init sta32x_init(void)
+{
+       return i2c_add_driver(&sta32x_i2c_driver);
+}
+module_init(sta32x_init);
+
+static void __exit sta32x_exit(void)
+{
+       i2c_del_driver(&sta32x_i2c_driver);
+}
+module_exit(sta32x_exit);
+
+MODULE_DESCRIPTION("ASoC STA32X driver");
+MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sta32x.h b/sound/soc/codecs/sta32x.h
new file mode 100644 (file)
index 0000000..b97ee5a
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Johannes Stezenbach <js@sig21.net>
+ *
+ * based on code from:
+ *     Wolfson Microelectronics PLC.
+ *     Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASOC_STA_32X_H
+#define _ASOC_STA_32X_H
+
+/* STA326 register addresses */
+
+#define STA32X_REGISTER_COUNT  0x2d
+
+#define STA32X_CONFA   0x00
+#define STA32X_CONFB    0x01
+#define STA32X_CONFC    0x02
+#define STA32X_CONFD    0x03
+#define STA32X_CONFE    0x04
+#define STA32X_CONFF    0x05
+#define STA32X_MMUTE    0x06
+#define STA32X_MVOL     0x07
+#define STA32X_C1VOL    0x08
+#define STA32X_C2VOL    0x09
+#define STA32X_C3VOL    0x0a
+#define STA32X_AUTO1    0x0b
+#define STA32X_AUTO2    0x0c
+#define STA32X_AUTO3    0x0d
+#define STA32X_C1CFG    0x0e
+#define STA32X_C2CFG    0x0f
+#define STA32X_C3CFG    0x10
+#define STA32X_TONE     0x11
+#define STA32X_L1AR     0x12
+#define STA32X_L1ATRT   0x13
+#define STA32X_L2AR     0x14
+#define STA32X_L2ATRT   0x15
+#define STA32X_CFADDR2  0x16
+#define STA32X_B1CF1    0x17
+#define STA32X_B1CF2    0x18
+#define STA32X_B1CF3    0x19
+#define STA32X_B2CF1    0x1a
+#define STA32X_B2CF2    0x1b
+#define STA32X_B2CF3    0x1c
+#define STA32X_A1CF1    0x1d
+#define STA32X_A1CF2    0x1e
+#define STA32X_A1CF3    0x1f
+#define STA32X_A2CF1    0x20
+#define STA32X_A2CF2    0x21
+#define STA32X_A2CF3    0x22
+#define STA32X_B0CF1    0x23
+#define STA32X_B0CF2    0x24
+#define STA32X_B0CF3    0x25
+#define STA32X_CFUD     0x26
+#define STA32X_MPCC1    0x27
+#define STA32X_MPCC2    0x28
+/* Reserved 0x29 */
+/* Reserved 0x2a */
+#define STA32X_Reserved 0x2a
+#define STA32X_FDRC1    0x2b
+#define STA32X_FDRC2    0x2c
+/* Reserved 0x2d */
+
+
+/* STA326 register field definitions */
+
+/* 0x00 CONFA */
+#define STA32X_CONFA_MCS_MASK  0x03
+#define STA32X_CONFA_MCS_SHIFT 0
+#define STA32X_CONFA_IR_MASK   0x18
+#define STA32X_CONFA_IR_SHIFT  3
+#define STA32X_CONFA_TWRB      0x20
+#define STA32X_CONFA_TWAB      0x40
+#define STA32X_CONFA_FDRB      0x80
+
+/* 0x01 CONFB */
+#define STA32X_CONFB_SAI_MASK  0x0f
+#define STA32X_CONFB_SAI_SHIFT 0
+#define STA32X_CONFB_SAIFB     0x10
+#define STA32X_CONFB_DSCKE     0x20
+#define STA32X_CONFB_C1IM      0x40
+#define STA32X_CONFB_C2IM      0x80
+
+/* 0x02 CONFC */
+#define STA32X_CONFC_OM_MASK   0x03
+#define STA32X_CONFC_OM_SHIFT  0
+#define STA32X_CONFC_CSZ_MASK  0x7c
+#define STA32X_CONFC_CSZ_SHIFT 2
+
+/* 0x03 CONFD */
+#define STA32X_CONFD_HPB       0x01
+#define STA32X_CONFD_HPB_SHIFT 0
+#define STA32X_CONFD_DEMP      0x02
+#define STA32X_CONFD_DEMP_SHIFT        1
+#define STA32X_CONFD_DSPB      0x04
+#define STA32X_CONFD_DSPB_SHIFT        2
+#define STA32X_CONFD_PSL       0x08
+#define STA32X_CONFD_PSL_SHIFT 3
+#define STA32X_CONFD_BQL       0x10
+#define STA32X_CONFD_BQL_SHIFT 4
+#define STA32X_CONFD_DRC       0x20
+#define STA32X_CONFD_DRC_SHIFT 5
+#define STA32X_CONFD_ZDE       0x40
+#define STA32X_CONFD_ZDE_SHIFT 6
+#define STA32X_CONFD_MME       0x80
+#define STA32X_CONFD_MME_SHIFT 7
+
+/* 0x04 CONFE */
+#define STA32X_CONFE_MPCV      0x01
+#define STA32X_CONFE_MPCV_SHIFT        0
+#define STA32X_CONFE_MPC       0x02
+#define STA32X_CONFE_MPC_SHIFT 1
+#define STA32X_CONFE_AME       0x08
+#define STA32X_CONFE_AME_SHIFT 3
+#define STA32X_CONFE_PWMS      0x10
+#define STA32X_CONFE_PWMS_SHIFT        4
+#define STA32X_CONFE_ZCE       0x40
+#define STA32X_CONFE_ZCE_SHIFT 6
+#define STA32X_CONFE_SVE       0x80
+#define STA32X_CONFE_SVE_SHIFT 7
+
+/* 0x05 CONFF */
+#define STA32X_CONFF_OCFG_MASK 0x03
+#define STA32X_CONFF_OCFG_SHIFT        0
+#define STA32X_CONFF_IDE       0x04
+#define STA32X_CONFF_IDE_SHIFT 3
+#define STA32X_CONFF_BCLE      0x08
+#define STA32X_CONFF_ECLE      0x20
+#define STA32X_CONFF_PWDN      0x40
+#define STA32X_CONFF_EAPD      0x80
+
+/* 0x06 MMUTE */
+#define STA32X_MMUTE_MMUTE     0x01
+
+/* 0x0b AUTO1 */
+#define STA32X_AUTO1_AMEQ_MASK 0x03
+#define STA32X_AUTO1_AMEQ_SHIFT        0
+#define STA32X_AUTO1_AMV_MASK  0xc0
+#define STA32X_AUTO1_AMV_SHIFT 2
+#define STA32X_AUTO1_AMGC_MASK 0x30
+#define STA32X_AUTO1_AMGC_SHIFT        4
+#define STA32X_AUTO1_AMPS      0x80
+
+/* 0x0c AUTO2 */
+#define STA32X_AUTO2_AMAME     0x01
+#define STA32X_AUTO2_AMAM_MASK 0x0e
+#define STA32X_AUTO2_AMAM_SHIFT        1
+#define STA32X_AUTO2_XO_MASK   0xf0
+#define STA32X_AUTO2_XO_SHIFT  4
+
+/* 0x0d AUTO3 */
+#define STA32X_AUTO3_PEQ_MASK  0x1f
+#define STA32X_AUTO3_PEQ_SHIFT 0
+
+/* 0x0e 0x0f 0x10 CxCFG */
+#define STA32X_CxCFG_TCB       0x01    /* only C1 and C2 */
+#define STA32X_CxCFG_TCB_SHIFT 0
+#define STA32X_CxCFG_EQBP      0x02    /* only C1 and C2 */
+#define STA32X_CxCFG_EQBP_SHIFT        1
+#define STA32X_CxCFG_VBP       0x03
+#define STA32X_CxCFG_VBP_SHIFT 2
+#define STA32X_CxCFG_BO                0x04
+#define STA32X_CxCFG_LS_MASK   0x30
+#define STA32X_CxCFG_LS_SHIFT  4
+#define STA32X_CxCFG_OM_MASK   0xc0
+#define STA32X_CxCFG_OM_SHIFT  6
+
+/* 0x11 TONE */
+#define STA32X_TONE_BTC_SHIFT  0
+#define STA32X_TONE_TTC_SHIFT  4
+
+/* 0x12 0x13 0x14 0x15 limiter attack/release */
+#define STA32X_LxA_SHIFT       0
+#define STA32X_LxR_SHIFT       4
+
+/* 0x26 CFUD */
+#define STA32X_CFUD_W1         0x01
+#define STA32X_CFUD_WA         0x02
+#define STA32X_CFUD_R1         0x04
+#define STA32X_CFUD_RA         0x08
+
+
+/* biquad filter coefficient table offsets */
+#define STA32X_C1_BQ_BASE      0
+#define STA32X_C2_BQ_BASE      20
+#define STA32X_CH_BQ_NUM       4
+#define STA32X_BQ_NUM_COEF     5
+#define STA32X_XO_HP_BQ_BASE   40
+#define STA32X_XO_LP_BQ_BASE   45
+#define STA32X_C1_PRESCALE     50
+#define STA32X_C2_PRESCALE     51
+#define STA32X_C1_POSTSCALE    52
+#define STA32X_C2_POSTSCALE    53
+#define STA32X_C3_POSTSCALE    54
+#define STA32X_TW_POSTSCALE    55
+#define STA32X_C1_MIX1         56
+#define STA32X_C1_MIX2         57
+#define STA32X_C2_MIX1         58
+#define STA32X_C2_MIX2         59
+#define STA32X_C3_MIX1         60
+#define STA32X_C3_MIX2         61
+
+#endif /* _ASOC_STA_32X_H */
index 789453d..0963c4c 100644 (file)
@@ -226,11 +226,13 @@ static const char *aic3x_adc_hpf[] =
 #define RDAC_ENUM      1
 #define LHPCOM_ENUM    2
 #define RHPCOM_ENUM    3
-#define LINE1L_ENUM    4
-#define LINE1R_ENUM    5
-#define LINE2L_ENUM    6
-#define LINE2R_ENUM    7
-#define ADC_HPF_ENUM   8
+#define LINE1L_2_L_ENUM        4
+#define LINE1L_2_R_ENUM        5
+#define LINE1R_2_L_ENUM        6
+#define LINE1R_2_R_ENUM        7
+#define LINE2L_ENUM    8
+#define LINE2R_ENUM    9
+#define ADC_HPF_ENUM   10
 
 static const struct soc_enum aic3x_enum[] = {
        SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux),
@@ -238,6 +240,8 @@ static const struct soc_enum aic3x_enum[] = {
        SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux),
        SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux),
        SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
+       SOC_ENUM_SINGLE(LINE1L_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
+       SOC_ENUM_SINGLE(LINE1R_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
        SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
        SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
        SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
@@ -490,12 +494,16 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
 };
 
 /* Left Line1 Mux */
-static const struct snd_kcontrol_new aic3x_left_line1_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]);
+static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_L_ENUM]);
+static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_R_ENUM]);
 
 /* Right Line1 Mux */
-static const struct snd_kcontrol_new aic3x_right_line1_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]);
+static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_R_ENUM]);
+static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_L_ENUM]);
 
 /* Left Line2 Mux */
 static const struct snd_kcontrol_new aic3x_left_line2_mux_controls =
@@ -535,9 +543,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
                           &aic3x_left_pga_mixer_controls[0],
                           ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
        SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
-                        &aic3x_left_line1_mux_controls),
+                        &aic3x_left_line1l_mux_controls),
        SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0,
-                        &aic3x_left_line1_mux_controls),
+                        &aic3x_left_line1r_mux_controls),
        SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_line2_mux_controls),
 
@@ -548,9 +556,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
                           &aic3x_right_pga_mixer_controls[0],
                           ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
        SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0,
-                        &aic3x_right_line1_mux_controls),
+                        &aic3x_right_line1l_mux_controls),
        SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
-                        &aic3x_right_line1_mux_controls),
+                        &aic3x_right_line1r_mux_controls),
        SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_line2_mux_controls),
 
index 4c33663..cd63bba 100644 (file)
@@ -954,9 +954,9 @@ static DECLARE_TLV_DB_SCALE(mic_preamp_tlv, -600, 600, 0);
 
 /*
  * MICGAIN volume control:
- * from -6 to 30 dB in 6 dB steps
+ * from 6 to 30 dB in 6 dB steps
  */
-static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0);
+static DECLARE_TLV_DB_SCALE(mic_amp_tlv, 600, 600, 0);
 
 /*
  * AFMGAIN volume control:
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c
new file mode 100644 (file)
index 0000000..a2a09f8
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * sound/soc/codecs/wm8782.c
+ * simple, strap-pin configured 24bit 2ch ADC
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Johannes Stezenbach <js@sig21.net>
+ *
+ * based on ad73311.c
+ * Copyright:  Analog Device Inc.
+ * Author:     Cliff Cai <cliff.cai@analog.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+static struct snd_soc_dai_driver wm8782_dai = {
+       .name = "wm8782",
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               /* For configurations with FSAMPEN=0 */
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                          SNDRV_PCM_FMTBIT_S20_3LE |
+                          SNDRV_PCM_FMTBIT_S24_LE,
+       },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8782;
+
+static __devinit int wm8782_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_wm8782, &wm8782_dai, 1);
+}
+
+static int __devexit wm8782_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver wm8782_codec_driver = {
+       .driver = {
+               .name = "wm8782",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8782_probe,
+       .remove = wm8782_remove,
+};
+
+static int __init wm8782_init(void)
+{
+       return platform_driver_register(&wm8782_codec_driver);
+}
+module_init(wm8782_init);
+
+static void __exit wm8782_exit(void)
+{
+       platform_driver_unregister(&wm8782_codec_driver);
+}
+module_exit(wm8782_exit);
+
+MODULE_DESCRIPTION("ASoC WM8782 driver");
+MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
+MODULE_LICENSE("GPL");
index 449ea09..082040e 100644 (file)
@@ -1167,6 +1167,7 @@ static int wm8900_resume(struct snd_soc_codec *codec)
                ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
                if (ret != 0) {
                        dev_err(codec->dev, "Failed to restart FLL\n");
+                       kfree(cache);
                        return ret;
                }
        }
index 9b3bba4..b085575 100644 (file)
@@ -2560,6 +2560,7 @@ static __devexit int wm8904_i2c_remove(struct i2c_client *client)
 static const struct i2c_device_id wm8904_i2c_id[] = {
        { "wm8904", WM8904 },
        { "wm8912", WM8912 },
+       { "wm8918", WM8904 },   /* Actually a subset, updates to follow */
        { }
 };
 MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
index e2ab4fa..423baa9 100644 (file)
 #define HPOUT2L 4
 #define HPOUT2R 8
 
-#define WM8915_NUM_SUPPLIES 6
+#define WM8915_NUM_SUPPLIES 4
 static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = {
-       "DCVDD",
        "DBVDD",
        "AVDD1",
        "AVDD2",
        "CPVDD",
-       "MICVDD",
 };
 
 struct wm8915_priv {
@@ -57,6 +55,7 @@ struct wm8915_priv {
        int ldo1ena;
 
        int sysclk;
+       int sysclk_src;
 
        int fll_src;
        int fll_fref;
@@ -76,6 +75,7 @@ struct wm8915_priv {
        struct wm8915_pdata pdata;
 
        int rx_rate[WM8915_AIFS];
+       int bclk_rate[WM8915_AIFS];
 
        /* Platform dependant ReTune mobile configuration */
        int num_retune_mobile_texts;
@@ -113,8 +113,6 @@ WM8915_REGULATOR_EVENT(0)
 WM8915_REGULATOR_EVENT(1)
 WM8915_REGULATOR_EVENT(2)
 WM8915_REGULATOR_EVENT(3)
-WM8915_REGULATOR_EVENT(4)
-WM8915_REGULATOR_EVENT(5)
 
 static const u16 wm8915_reg[WM8915_MAX_REGISTER] = {
        [WM8915_SOFTWARE_RESET] = 0x8915,
@@ -1565,6 +1563,50 @@ static int wm8915_reset(struct snd_soc_codec *codec)
        return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915);
 }
 
+static const int bclk_divs[] = {
+       1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
+};
+
+static void wm8915_update_bclk(struct snd_soc_codec *codec)
+{
+       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       int aif, best, cur_val, bclk_rate, bclk_reg, i;
+
+       /* Don't bother if we're in a low frequency idle mode that
+        * can't support audio.
+        */
+       if (wm8915->sysclk < 64000)
+               return;
+
+       for (aif = 0; aif < WM8915_AIFS; aif++) {
+               switch (aif) {
+               case 0:
+                       bclk_reg = WM8915_AIF1_BCLK;
+                       break;
+               case 1:
+                       bclk_reg = WM8915_AIF2_BCLK;
+                       break;
+               }
+
+               bclk_rate = wm8915->bclk_rate[aif];
+
+               /* Pick a divisor for BCLK as close as we can get to ideal */
+               best = 0;
+               for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+                       cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate;
+                       if (cur_val < 0) /* BCLK table is sorted */
+                               break;
+                       best = i;
+               }
+               bclk_rate = wm8915->sysclk / bclk_divs[best];
+               dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+                       bclk_divs[best], bclk_rate);
+
+               snd_soc_update_bits(codec, bclk_reg,
+                                   WM8915_AIF1_BCLK_DIV_MASK, best);
+       }
+}
+
 static int wm8915_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
@@ -1717,10 +1759,6 @@ static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
-static const int bclk_divs[] = {
-       1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
-};
-
 static const int dsp_divs[] = {
        48000, 32000, 16000, 8000
 };
@@ -1731,17 +1769,11 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int bits, i, bclk_rate, best, cur_val;
+       int bits, i, bclk_rate;
        int aifdata = 0;
-       int bclk = 0;
        int lrclk = 0;
        int dsp = 0;
-       int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift;
-
-       if (!wm8915->sysclk) {
-               dev_err(codec->dev, "SYSCLK not configured\n");
-               return -EINVAL;
-       }
+       int aifdata_reg, lrclk_reg, dsp_shift;
 
        switch (dai->id) {
        case 0:
@@ -1753,7 +1785,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream,
                        aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1;
                        lrclk_reg = WM8915_AIF1_TX_LRCLK_1;
                }
-               bclk_reg = WM8915_AIF1_BCLK;
                dsp_shift = 0;
                break;
        case 1:
@@ -1765,7 +1796,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream,
                        aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1;
                        lrclk_reg = WM8915_AIF2_TX_LRCLK_1;
                }
-               bclk_reg = WM8915_AIF2_BCLK;
                dsp_shift = WM8915_DSP2_DIV_SHIFT;
                break;
        default:
@@ -1779,6 +1809,9 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream,
                return bclk_rate;
        }
 
+       wm8915->bclk_rate[dai->id] = bclk_rate;
+       wm8915->rx_rate[dai->id] = params_rate(params);
+
        /* Needs looking at for TDM */
        bits = snd_pcm_format_width(params_format(params));
        if (bits < 0)
@@ -1796,18 +1829,7 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream,
        }
        dsp |= i << dsp_shift;
 
-       /* Pick a divisor for BCLK as close as we can get to ideal */
-       best = 0;
-       for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
-               cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate;
-               if (cur_val < 0) /* BCLK table is sorted */
-                       break;
-               best = i;
-       }
-       bclk_rate = wm8915->sysclk / bclk_divs[best];
-       dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
-               bclk_divs[best], bclk_rate);
-       bclk |= best;
+       wm8915_update_bclk(codec);
 
        lrclk = bclk_rate / params_rate(params);
        dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
@@ -1817,14 +1839,11 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream,
                            WM8915_AIF1TX_WL_MASK |
                            WM8915_AIF1TX_SLOT_LEN_MASK,
                            aifdata);
-       snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk);
        snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK,
                            lrclk);
        snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2,
                            WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp);
 
-       wm8915->rx_rate[dai->id] = params_rate(params);
-
        return 0;
 }
 
@@ -1838,6 +1857,9 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai,
        int src;
        int old;
 
+       if (freq == wm8915->sysclk && clk_id == wm8915->sysclk_src)
+               return 0;
+
        /* Disable SYSCLK while we reconfigure */
        old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA;
        snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
@@ -1882,6 +1904,8 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
+       wm8915_update_bclk(codec);
+
        snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
                            WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK,
                            src << WM8915_SYSCLK_SRC_SHIFT | ratediv);
@@ -1889,6 +1913,8 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai,
        snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
                            WM8915_SYSCLK_ENA, old);
 
+       wm8915->sysclk_src = clk_id;
+
        return 0;
 }
 
@@ -2007,6 +2033,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                          unsigned int Fref, unsigned int Fout)
 {
        struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
        struct _fll_div fll_div;
        unsigned long timeout;
        int ret, reg;
@@ -2093,7 +2120,18 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
        else
                timeout = msecs_to_jiffies(2);
 
-       wait_for_completion_timeout(&wm8915->fll_lock, timeout);
+       /* Allow substantially longer if we've actually got the IRQ */
+       if (i2c->irq)
+               timeout *= 1000;
+
+       ret = wait_for_completion_timeout(&wm8915->fll_lock, timeout);
+
+       if (ret == 0 && i2c->irq) {
+               dev_err(codec->dev, "Timed out waiting for FLL\n");
+               ret = -ETIMEDOUT;
+       } else {
+               ret = 0;
+       }
 
        dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
@@ -2101,7 +2139,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
        wm8915->fll_fout = Fout;
        wm8915->fll_src = source;
 
-       return 0;
+       return ret;
 }
 
 #ifdef CONFIG_GPIOLIB
@@ -2293,6 +2331,12 @@ static void wm8915_micd(struct snd_soc_codec *codec)
                                    SND_JACK_HEADSET | SND_JACK_BTN_0);
                wm8915->jack_mic = true;
                wm8915->detecting = false;
+
+               /* Increase poll rate to give better responsiveness
+                * for buttons */
+               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+                                   WM8915_MICD_RATE_MASK,
+                                   5 << WM8915_MICD_RATE_SHIFT);
        }
 
        /* If we detected a lower impedence during initial startup
@@ -2333,15 +2377,17 @@ static void wm8915_micd(struct snd_soc_codec *codec)
                                            SND_JACK_HEADPHONE,
                                            SND_JACK_HEADSET |
                                            SND_JACK_BTN_0);
+
+                       /* Increase the detection rate a bit for
+                        * responsiveness.
+                        */
+                       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+                                           WM8915_MICD_RATE_MASK,
+                                           7 << WM8915_MICD_RATE_SHIFT);
+
                        wm8915->detecting = false;
                }
        }
-
-       /* Increase poll rate to give better responsiveness for buttons */
-       if (!wm8915->detecting)
-               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                                   WM8915_MICD_RATE_MASK,
-                                   5 << WM8915_MICD_RATE_SHIFT);
 }
 
 static irqreturn_t wm8915_irq(int irq, void *data)
@@ -2383,6 +2429,20 @@ static irqreturn_t wm8915_irq(int irq, void *data)
        }
 }
 
+static irqreturn_t wm8915_edge_irq(int irq, void *data)
+{
+       irqreturn_t ret = IRQ_NONE;
+       irqreturn_t val;
+
+       do {
+               val = wm8915_irq(irq, data);
+               if (val != IRQ_NONE)
+                       ret = val;
+       } while (val != IRQ_NONE);
+
+       return ret;
+}
+
 static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec)
 {
        struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
@@ -2482,8 +2542,6 @@ static int wm8915_probe(struct snd_soc_codec *codec)
        wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1;
        wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2;
        wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3;
-       wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4;
-       wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5;
 
        /* This should really be moved into the regulator core */
        for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) {
@@ -2709,8 +2767,14 @@ static int wm8915_probe(struct snd_soc_codec *codec)
 
                irq_flags |= IRQF_ONESHOT;
 
-               ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
-                                          irq_flags, "wm8915", codec);
+               if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+                       ret = request_threaded_irq(i2c->irq, NULL,
+                                                  wm8915_edge_irq,
+                                                  irq_flags, "wm8915", codec);
+               else
+                       ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
+                                                  irq_flags, "wm8915", codec);
+
                if (ret == 0) {
                        /* Unmask the interrupt */
                        snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
index 25580e3..056daa0 100644 (file)
@@ -297,8 +297,6 @@ static int wm8940_add_widgets(struct snd_soc_codec *codec)
        if (ret)
                goto error_ret;
        ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-       if (ret)
-               goto error_ret;
 
 error_ret:
        return ret;
@@ -683,8 +681,6 @@ static int wm8940_resume(struct snd_soc_codec *codec)
                }
        }
        ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       if (ret)
-               goto error_ret;
 
 error_ret:
        return ret;
@@ -730,9 +726,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
        if (ret)
                return ret;
        ret = wm8940_add_widgets(codec);
-       if (ret)
-               return ret;
-
        return ret;
 }
 
index 5e05eed..8499c56 100644 (file)
@@ -78,6 +78,8 @@ struct wm8962_priv {
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip gpio_chip;
 #endif
+
+       int irq;
 };
 
 /* We can't use the same notifier block for more than one supply and
@@ -1982,6 +1984,7 @@ static const unsigned int classd_tlv[] = {
        0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
        7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
 };
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 
 /* The VU bits for the headphones are in a different register to the mute
  * bits and only take effect on the PGA if it is actually powered.
@@ -2119,6 +2122,18 @@ SOC_SINGLE_TLV("HPMIXR MIXINR Volume", WM8962_HEADPHONE_MIXER_4,
 
 SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0,
               classd_tlv),
+
+SOC_SINGLE("EQ Switch", WM8962_EQ1, WM8962_EQ_ENA_SHIFT, 1, 0),
+SOC_DOUBLE_R_TLV("EQ1 Volume", WM8962_EQ2, WM8962_EQ22,
+                WM8962_EQL_B1_GAIN_SHIFT, 31, 0, eq_tlv),
+SOC_DOUBLE_R_TLV("EQ2 Volume", WM8962_EQ2, WM8962_EQ22,
+                WM8962_EQL_B2_GAIN_SHIFT, 31, 0, eq_tlv),
+SOC_DOUBLE_R_TLV("EQ3 Volume", WM8962_EQ2, WM8962_EQ22,
+                WM8962_EQL_B3_GAIN_SHIFT, 31, 0, eq_tlv),
+SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23,
+                WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv),
+SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,
+                WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv),
 };
 
 static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
@@ -2184,6 +2199,8 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_codec *codec = w->codec;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       unsigned long timeout;
        int src;
        int fll;
 
@@ -2203,9 +2220,19 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               if (fll)
+               if (fll) {
                        snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
                                            WM8962_FLL_ENA, WM8962_FLL_ENA);
+                       if (wm8962->irq) {
+                               timeout = msecs_to_jiffies(5);
+                               timeout = wait_for_completion_timeout(&wm8962->fll_lock,
+                                                                     timeout);
+
+                               if (timeout == 0)
+                                       dev_err(codec->dev,
+                                               "Timed out starting FLL\n");
+                       }
+               }
                break;
 
        case SND_SOC_DAPM_POST_PMD:
@@ -2763,18 +2790,44 @@ static const int bclk_divs[] = {
        1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32
 };
 
+static const int sysclk_rates[] = {
+       64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536,
+};
+
 static void wm8962_configure_bclk(struct snd_soc_codec *codec)
 {
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        int dspclk, i;
        int clocking2 = 0;
+       int clocking4 = 0;
        int aif2 = 0;
 
-       if (!wm8962->bclk) {
-               dev_dbg(codec->dev, "No BCLK rate configured\n");
+       if (!wm8962->sysclk_rate) {
+               dev_dbg(codec->dev, "No SYSCLK configured\n");
+               return;
+       }
+
+       if (!wm8962->bclk || !wm8962->lrclk) {
+               dev_dbg(codec->dev, "No audio clocks configured\n");
                return;
        }
 
+       for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) {
+               if (sysclk_rates[i] == wm8962->sysclk_rate / wm8962->lrclk) {
+                       clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(sysclk_rates)) {
+               dev_err(codec->dev, "Unsupported sysclk ratio %d\n",
+                       wm8962->sysclk_rate / wm8962->lrclk);
+               return;
+       }
+
+       snd_soc_update_bits(codec, WM8962_CLOCKING_4,
+                           WM8962_SYSCLK_RATE_MASK, clocking4);
+
        dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
        if (dspclk < 0) {
                dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);
@@ -2844,6 +2897,8 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                /* VMID 2*50k */
                snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
                                    WM8962_VMID_SEL_MASK, 0x80);
+
+               wm8962_configure_bclk(codec);
                break;
 
        case SND_SOC_BIAS_STANDBY:
@@ -2876,8 +2931,6 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                        snd_soc_update_bits(codec, WM8962_CLOCKING2,
                                            WM8962_CLKREG_OVD,
                                            WM8962_CLKREG_OVD);
-
-                       wm8962_configure_bclk(codec);
                }
 
                /* VMID 2*250k */
@@ -2918,10 +2971,6 @@ static const struct {
        { 96000, 6 },
 };
 
-static const int sysclk_rates[] = {
-       64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536,
-};
-
 static int wm8962_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
@@ -2929,41 +2978,27 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_codec *codec = rtd->codec;
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       int rate = params_rate(params);
        int i;
        int aif0 = 0;
        int adctl3 = 0;
-       int clocking4 = 0;
 
        wm8962->bclk = snd_soc_params_to_bclk(params);
        wm8962->lrclk = params_rate(params);
 
        for (i = 0; i < ARRAY_SIZE(sr_vals); i++) {
-               if (sr_vals[i].rate == rate) {
+               if (sr_vals[i].rate == wm8962->lrclk) {
                        adctl3 |= sr_vals[i].reg;
                        break;
                }
        }
        if (i == ARRAY_SIZE(sr_vals)) {
-               dev_err(codec->dev, "Unsupported rate %dHz\n", rate);
+               dev_err(codec->dev, "Unsupported rate %dHz\n", wm8962->lrclk);
                return -EINVAL;
        }
 
-       if (rate % 8000 == 0)
+       if (wm8962->lrclk % 8000 == 0)
                adctl3 |= WM8962_SAMPLE_RATE_INT_MODE;
 
-       for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) {
-               if (sysclk_rates[i] == wm8962->sysclk_rate / rate) {
-                       clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT;
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(sysclk_rates)) {
-               dev_err(codec->dev, "Unsupported sysclk ratio %d\n",
-                       wm8962->sysclk_rate / rate);
-               return -EINVAL;
-       }
-
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                break;
@@ -2985,8 +3020,6 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
        snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3,
                            WM8962_SAMPLE_RATE_INT_MODE |
                            WM8962_SAMPLE_RATE_MASK, adctl3);
-       snd_soc_update_bits(codec, WM8962_CLOCKING_4,
-                           WM8962_SYSCLK_RATE_MASK, clocking4);
 
        wm8962_configure_bclk(codec);
 
@@ -3261,16 +3294,31 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 
        dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
-       /* This should be a massive overestimate */
-       timeout = msecs_to_jiffies(1);
+       ret = 0;
+
+       if (fll1 & WM8962_FLL_ENA) {
+               /* This should be a massive overestimate but go even
+                * higher if we'll error out
+                */
+               if (wm8962->irq)
+                       timeout = msecs_to_jiffies(5);
+               else
+                       timeout = msecs_to_jiffies(1);
+
+               timeout = wait_for_completion_timeout(&wm8962->fll_lock,
+                                                     timeout);
 
-       wait_for_completion_timeout(&wm8962->fll_lock, timeout);
+               if (timeout == 0 && wm8962->irq) {
+                       dev_err(codec->dev, "FLL lock timed out");
+                       ret = -ETIMEDOUT;
+               }
+       }
 
        wm8962->fll_fref = Fref;
        wm8962->fll_fout = Fout;
        wm8962->fll_src = source;
 
-       return 0;
+       return ret;
 }
 
 static int wm8962_mute(struct snd_soc_dai *dai, int mute)
@@ -3731,8 +3779,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        int ret;
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
-       struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
-                                             dev);
        u16 *reg_cache = codec->reg_cache;
        int i, trigger, irq_pol;
        bool dmicclk, dmicdat;
@@ -3871,6 +3917,9 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME,
                            WM8962_HPOUT_VU, WM8962_HPOUT_VU);
 
+       /* Stereo control for EQ */
+       snd_soc_update_bits(codec, WM8962_EQ1, WM8962_EQ_SHARED_COEFF, 0);
+
        wm8962_add_widgets(codec);
 
        /* Save boards having to disable DMIC when not in use */
@@ -3899,7 +3948,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        wm8962_init_beep(codec);
        wm8962_init_gpio(codec);
 
-       if (i2c->irq) {
+       if (wm8962->irq) {
                if (pdata && pdata->irq_active_low) {
                        trigger = IRQF_TRIGGER_LOW;
                        irq_pol = WM8962_IRQ_POL;
@@ -3911,12 +3960,13 @@ static int wm8962_probe(struct snd_soc_codec *codec)
                snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL,
                                    WM8962_IRQ_POL, irq_pol);
 
-               ret = request_threaded_irq(i2c->irq, NULL, wm8962_irq,
+               ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq,
                                           trigger | IRQF_ONESHOT,
                                           "wm8962", codec);
                if (ret != 0) {
                        dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
-                               i2c->irq, ret);
+                               wm8962->irq, ret);
+                       wm8962->irq = 0;
                        /* Non-fatal */
                } else {
                        /* Enable some IRQs by default */
@@ -3941,12 +3991,10 @@ err:
 static int wm8962_remove(struct snd_soc_codec *codec)
 {
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
-                                             dev);
        int i;
 
-       if (i2c->irq)
-               free_irq(i2c->irq, codec);
+       if (wm8962->irq)
+               free_irq(wm8962->irq, codec);
 
        cancel_delayed_work_sync(&wm8962->mic_work);
 
@@ -3986,6 +4034,8 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, wm8962);
 
+       wm8962->irq = i2c->irq;
+
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm8962, &wm8962_dai, 1);
        if (ret < 0)
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
new file mode 100644 (file)
index 0000000..17f04ec
--- /dev/null
@@ -0,0 +1,1203 @@
+/*
+ * wm8983.c  --  WM8983 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8983.h"
+
+static const u16 wm8983_reg_defs[WM8983_MAX_REGISTER + 1] = {
+       [0x00] = 0x0000,     /* R0  - Software Reset */
+       [0x01] = 0x0000,     /* R1  - Power management 1 */
+       [0x02] = 0x0000,     /* R2  - Power management 2 */
+       [0x03] = 0x0000,     /* R3  - Power management 3 */
+       [0x04] = 0x0050,     /* R4  - Audio Interface */
+       [0x05] = 0x0000,     /* R5  - Companding control */
+       [0x06] = 0x0140,     /* R6  - Clock Gen control */
+       [0x07] = 0x0000,     /* R7  - Additional control */
+       [0x08] = 0x0000,     /* R8  - GPIO Control */
+       [0x09] = 0x0000,     /* R9  - Jack Detect Control 1 */
+       [0x0A] = 0x0000,     /* R10 - DAC Control */
+       [0x0B] = 0x00FF,     /* R11 - Left DAC digital Vol */
+       [0x0C] = 0x00FF,     /* R12 - Right DAC digital vol */
+       [0x0D] = 0x0000,     /* R13 - Jack Detect Control 2 */
+       [0x0E] = 0x0100,     /* R14 - ADC Control */
+       [0x0F] = 0x00FF,     /* R15 - Left ADC Digital Vol */
+       [0x10] = 0x00FF,     /* R16 - Right ADC Digital Vol */
+       [0x12] = 0x012C,     /* R18 - EQ1 - low shelf */
+       [0x13] = 0x002C,     /* R19 - EQ2 - peak 1 */
+       [0x14] = 0x002C,     /* R20 - EQ3 - peak 2 */
+       [0x15] = 0x002C,     /* R21 - EQ4 - peak 3 */
+       [0x16] = 0x002C,     /* R22 - EQ5 - high shelf */
+       [0x18] = 0x0032,     /* R24 - DAC Limiter 1 */
+       [0x19] = 0x0000,     /* R25 - DAC Limiter 2 */
+       [0x1B] = 0x0000,     /* R27 - Notch Filter 1 */
+       [0x1C] = 0x0000,     /* R28 - Notch Filter 2 */
+       [0x1D] = 0x0000,     /* R29 - Notch Filter 3 */
+       [0x1E] = 0x0000,     /* R30 - Notch Filter 4 */
+       [0x20] = 0x0038,     /* R32 - ALC control 1 */
+       [0x21] = 0x000B,     /* R33 - ALC control 2 */
+       [0x22] = 0x0032,     /* R34 - ALC control 3 */
+       [0x23] = 0x0000,     /* R35 - Noise Gate */
+       [0x24] = 0x0008,     /* R36 - PLL N */
+       [0x25] = 0x000C,     /* R37 - PLL K 1 */
+       [0x26] = 0x0093,     /* R38 - PLL K 2 */
+       [0x27] = 0x00E9,     /* R39 - PLL K 3 */
+       [0x29] = 0x0000,     /* R41 - 3D control */
+       [0x2A] = 0x0000,     /* R42 - OUT4 to ADC */
+       [0x2B] = 0x0000,     /* R43 - Beep control */
+       [0x2C] = 0x0033,     /* R44 - Input ctrl */
+       [0x2D] = 0x0010,     /* R45 - Left INP PGA gain ctrl */
+       [0x2E] = 0x0010,     /* R46 - Right INP PGA gain ctrl */
+       [0x2F] = 0x0100,     /* R47 - Left ADC BOOST ctrl */
+       [0x30] = 0x0100,     /* R48 - Right ADC BOOST ctrl */
+       [0x31] = 0x0002,     /* R49 - Output ctrl */
+       [0x32] = 0x0001,     /* R50 - Left mixer ctrl */
+       [0x33] = 0x0001,     /* R51 - Right mixer ctrl */
+       [0x34] = 0x0039,     /* R52 - LOUT1 (HP) volume ctrl */
+       [0x35] = 0x0039,     /* R53 - ROUT1 (HP) volume ctrl */
+       [0x36] = 0x0039,     /* R54 - LOUT2 (SPK) volume ctrl */
+       [0x37] = 0x0039,     /* R55 - ROUT2 (SPK) volume ctrl */
+       [0x38] = 0x0001,     /* R56 - OUT3 mixer ctrl */
+       [0x39] = 0x0001,     /* R57 - OUT4 (MONO) mix ctrl */
+       [0x3D] = 0x0000      /* R61 - BIAS CTRL */
+};
+
+static const struct wm8983_reg_access {
+       u16 read; /* Mask of readable bits */
+       u16 write; /* Mask of writable bits */
+} wm8983_access_masks[WM8983_MAX_REGISTER + 1] = {
+       [0x00] = { 0x0000, 0x01FF }, /* R0  - Software Reset */
+       [0x01] = { 0x0000, 0x01FF }, /* R1  - Power management 1 */
+       [0x02] = { 0x0000, 0x01FF }, /* R2  - Power management 2 */
+       [0x03] = { 0x0000, 0x01EF }, /* R3  - Power management 3 */
+       [0x04] = { 0x0000, 0x01FF }, /* R4  - Audio Interface */
+       [0x05] = { 0x0000, 0x003F }, /* R5  - Companding control */
+       [0x06] = { 0x0000, 0x01FD }, /* R6  - Clock Gen control */
+       [0x07] = { 0x0000, 0x000F }, /* R7  - Additional control */
+       [0x08] = { 0x0000, 0x003F }, /* R8  - GPIO Control */
+       [0x09] = { 0x0000, 0x0070 }, /* R9  - Jack Detect Control 1 */
+       [0x0A] = { 0x0000, 0x004F }, /* R10 - DAC Control */
+       [0x0B] = { 0x0000, 0x01FF }, /* R11 - Left DAC digital Vol */
+       [0x0C] = { 0x0000, 0x01FF }, /* R12 - Right DAC digital vol */
+       [0x0D] = { 0x0000, 0x00FF }, /* R13 - Jack Detect Control 2 */
+       [0x0E] = { 0x0000, 0x01FB }, /* R14 - ADC Control */
+       [0x0F] = { 0x0000, 0x01FF }, /* R15 - Left ADC Digital Vol */
+       [0x10] = { 0x0000, 0x01FF }, /* R16 - Right ADC Digital Vol */
+       [0x12] = { 0x0000, 0x017F }, /* R18 - EQ1 - low shelf */
+       [0x13] = { 0x0000, 0x017F }, /* R19 - EQ2 - peak 1 */
+       [0x14] = { 0x0000, 0x017F }, /* R20 - EQ3 - peak 2 */
+       [0x15] = { 0x0000, 0x017F }, /* R21 - EQ4 - peak 3 */
+       [0x16] = { 0x0000, 0x007F }, /* R22 - EQ5 - high shelf */
+       [0x18] = { 0x0000, 0x01FF }, /* R24 - DAC Limiter 1 */
+       [0x19] = { 0x0000, 0x007F }, /* R25 - DAC Limiter 2 */
+       [0x1B] = { 0x0000, 0x01FF }, /* R27 - Notch Filter 1 */
+       [0x1C] = { 0x0000, 0x017F }, /* R28 - Notch Filter 2 */
+       [0x1D] = { 0x0000, 0x017F }, /* R29 - Notch Filter 3 */
+       [0x1E] = { 0x0000, 0x017F }, /* R30 - Notch Filter 4 */
+       [0x20] = { 0x0000, 0x01BF }, /* R32 - ALC control 1 */
+       [0x21] = { 0x0000, 0x00FF }, /* R33 - ALC control 2 */
+       [0x22] = { 0x0000, 0x01FF }, /* R34 - ALC control 3 */
+       [0x23] = { 0x0000, 0x000F }, /* R35 - Noise Gate */
+       [0x24] = { 0x0000, 0x001F }, /* R36 - PLL N */
+       [0x25] = { 0x0000, 0x003F }, /* R37 - PLL K 1 */
+       [0x26] = { 0x0000, 0x01FF }, /* R38 - PLL K 2 */
+       [0x27] = { 0x0000, 0x01FF }, /* R39 - PLL K 3 */
+       [0x29] = { 0x0000, 0x000F }, /* R41 - 3D control */
+       [0x2A] = { 0x0000, 0x01E7 }, /* R42 - OUT4 to ADC */
+       [0x2B] = { 0x0000, 0x01BF }, /* R43 - Beep control */
+       [0x2C] = { 0x0000, 0x0177 }, /* R44 - Input ctrl */
+       [0x2D] = { 0x0000, 0x01FF }, /* R45 - Left INP PGA gain ctrl */
+       [0x2E] = { 0x0000, 0x01FF }, /* R46 - Right INP PGA gain ctrl */
+       [0x2F] = { 0x0000, 0x0177 }, /* R47 - Left ADC BOOST ctrl */
+       [0x30] = { 0x0000, 0x0177 }, /* R48 - Right ADC BOOST ctrl */
+       [0x31] = { 0x0000, 0x007F }, /* R49 - Output ctrl */
+       [0x32] = { 0x0000, 0x01FF }, /* R50 - Left mixer ctrl */
+       [0x33] = { 0x0000, 0x01FF }, /* R51 - Right mixer ctrl */
+       [0x34] = { 0x0000, 0x01FF }, /* R52 - LOUT1 (HP) volume ctrl */
+       [0x35] = { 0x0000, 0x01FF }, /* R53 - ROUT1 (HP) volume ctrl */
+       [0x36] = { 0x0000, 0x01FF }, /* R54 - LOUT2 (SPK) volume ctrl */
+       [0x37] = { 0x0000, 0x01FF }, /* R55 - ROUT2 (SPK) volume ctrl */
+       [0x38] = { 0x0000, 0x004F }, /* R56 - OUT3 mixer ctrl */
+       [0x39] = { 0x0000, 0x00FF }, /* R57 - OUT4 (MONO) mix ctrl */
+       [0x3D] = { 0x0000, 0x0100 }  /* R61 - BIAS CTRL */
+};
+
+/* vol/gain update regs */
+static const int vol_update_regs[] = {
+       WM8983_LEFT_DAC_DIGITAL_VOL,
+       WM8983_RIGHT_DAC_DIGITAL_VOL,
+       WM8983_LEFT_ADC_DIGITAL_VOL,
+       WM8983_RIGHT_ADC_DIGITAL_VOL,
+       WM8983_LOUT1_HP_VOLUME_CTRL,
+       WM8983_ROUT1_HP_VOLUME_CTRL,
+       WM8983_LOUT2_SPK_VOLUME_CTRL,
+       WM8983_ROUT2_SPK_VOLUME_CTRL,
+       WM8983_LEFT_INP_PGA_GAIN_CTRL,
+       WM8983_RIGHT_INP_PGA_GAIN_CTRL
+};
+
+struct wm8983_priv {
+       enum snd_soc_control_type control_type;
+       u32 sysclk;
+       u32 bclk;
+};
+
+static const struct {
+       int div;
+       int ratio;
+} fs_ratios[] = {
+       { 10, 128 },
+       { 15, 192 },
+       { 20, 256 },
+       { 30, 384 },
+       { 40, 512 },
+       { 60, 768 },
+       { 80, 1024 },
+       { 120, 1536 }
+};
+
+static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 };
+
+static const int bclk_divs[] = {
+       1, 2, 4, 8, 16, 32
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol);
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_thresh_tlv, -600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_boost_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_min_tlv, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tar_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(aux_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
+
+static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
+static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7,
+                                 alc_sel_text);
+
+static const char *alc_mode_text[] = { "ALC", "Limiter" };
+static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8,
+                                 alc_mode_text);
+
+static const char *filter_mode_text[] = { "Audio", "Application" };
+static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7,
+                                 filter_mode_text);
+
+static const char *eq_bw_text[] = { "Narrow", "Wide" };
+static const char *eqmode_text[] = { "Capture", "Playback" };
+static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+
+static const char *eq1_cutoff_text[] = {
+       "80Hz", "105Hz", "135Hz", "175Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5,
+                                 eq1_cutoff_text);
+static const char *eq2_cutoff_text[] = {
+       "230Hz", "300Hz", "385Hz", "500Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5,
+                                 eq2_cutoff_text);
+static const char *eq3_cutoff_text[] = {
+       "650Hz", "850Hz", "1.1kHz", "1.4kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5,
+                                 eq3_cutoff_text);
+static const char *eq4_cutoff_text[] = {
+       "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5,
+                                 eq4_cutoff_text);
+static const char *eq5_cutoff_text[] = {
+       "5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5,
+                                 eq5_cutoff_text);
+
+static const char *speaker_mode_text[] = { "Class A/B", "Class D" };
+static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
+
+static const char *depth_3d_text[] = {
+       "Off",
+       "6.67%",
+       "13.3%",
+       "20%",
+       "26.7%",
+       "33.3%",
+       "40%",
+       "46.6%",
+       "53.3%",
+       "60%",
+       "66.7%",
+       "73.3%",
+       "80%",
+       "86.7%",
+       "93.3%",
+       "100%"
+};
+static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0,
+                                 depth_3d_text);
+
+static const struct snd_kcontrol_new wm8983_snd_controls[] = {
+       SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL,
+                  0, 1, 0),
+
+       SOC_ENUM("ALC Capture Function", alc_sel),
+       SOC_SINGLE_TLV("ALC Capture Max Volume", WM8983_ALC_CONTROL_1,
+                      3, 7, 0, alc_max_tlv),
+       SOC_SINGLE_TLV("ALC Capture Min Volume", WM8983_ALC_CONTROL_1,
+                      0, 7, 0, alc_min_tlv),
+       SOC_SINGLE_TLV("ALC Capture Target Volume", WM8983_ALC_CONTROL_2,
+                      0, 15, 0, alc_tar_tlv),
+       SOC_SINGLE("ALC Capture Attack", WM8983_ALC_CONTROL_3, 0, 10, 0),
+       SOC_SINGLE("ALC Capture Hold", WM8983_ALC_CONTROL_2, 4, 10, 0),
+       SOC_SINGLE("ALC Capture Decay", WM8983_ALC_CONTROL_3, 4, 10, 0),
+       SOC_ENUM("ALC Mode", alc_mode),
+       SOC_SINGLE("ALC Capture NG Switch", WM8983_NOISE_GATE,
+                  3, 1, 0),
+       SOC_SINGLE("ALC Capture NG Threshold", WM8983_NOISE_GATE,
+                  0, 7, 1),
+
+       SOC_DOUBLE_R_TLV("Capture Volume", WM8983_LEFT_ADC_DIGITAL_VOL,
+                        WM8983_RIGHT_ADC_DIGITAL_VOL, 0, 255, 0, adc_tlv),
+       SOC_DOUBLE_R("Capture PGA ZC Switch", WM8983_LEFT_INP_PGA_GAIN_CTRL,
+                    WM8983_RIGHT_INP_PGA_GAIN_CTRL, 7, 1, 0),
+       SOC_DOUBLE_R_TLV("Capture PGA Volume", WM8983_LEFT_INP_PGA_GAIN_CTRL,
+                        WM8983_RIGHT_INP_PGA_GAIN_CTRL, 0, 63, 0, pga_vol_tlv),
+
+       SOC_DOUBLE_R_TLV("Capture PGA Boost Volume",
+                        WM8983_LEFT_ADC_BOOST_CTRL, WM8983_RIGHT_ADC_BOOST_CTRL,
+                        8, 1, 0, pga_boost_tlv),
+
+       SOC_DOUBLE("ADC Inversion Switch", WM8983_ADC_CONTROL, 0, 1, 1, 0),
+       SOC_SINGLE("ADC 128x Oversampling Switch", WM8983_ADC_CONTROL, 8, 1, 0),
+
+       SOC_DOUBLE_R_TLV("Playback Volume", WM8983_LEFT_DAC_DIGITAL_VOL,
+                        WM8983_RIGHT_DAC_DIGITAL_VOL, 0, 255, 0, dac_tlv),
+
+       SOC_SINGLE("DAC Playback Limiter Switch", WM8983_DAC_LIMITER_1, 8, 1, 0),
+       SOC_SINGLE("DAC Playback Limiter Decay", WM8983_DAC_LIMITER_1, 4, 10, 0),
+       SOC_SINGLE("DAC Playback Limiter Attack", WM8983_DAC_LIMITER_1, 0, 11, 0),
+       SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8983_DAC_LIMITER_2,
+                      4, 7, 1, lim_thresh_tlv),
+       SOC_SINGLE_TLV("DAC Playback Limiter Boost Volume", WM8983_DAC_LIMITER_2,
+                      0, 12, 0, lim_boost_tlv),
+       SOC_DOUBLE("DAC Inversion Switch", WM8983_DAC_CONTROL, 0, 1, 1, 0),
+       SOC_SINGLE("DAC Auto Mute Switch", WM8983_DAC_CONTROL, 2, 1, 0),
+       SOC_SINGLE("DAC 128x Oversampling Switch", WM8983_DAC_CONTROL, 3, 1, 0),
+
+       SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8983_LOUT1_HP_VOLUME_CTRL,
+                        WM8983_ROUT1_HP_VOLUME_CTRL, 0, 63, 0, out_tlv),
+       SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8983_LOUT1_HP_VOLUME_CTRL,
+                    WM8983_ROUT1_HP_VOLUME_CTRL, 7, 1, 0),
+       SOC_DOUBLE_R("Headphone Switch", WM8983_LOUT1_HP_VOLUME_CTRL,
+                    WM8983_ROUT1_HP_VOLUME_CTRL, 6, 1, 1),
+
+       SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8983_LOUT2_SPK_VOLUME_CTRL,
+                        WM8983_ROUT2_SPK_VOLUME_CTRL, 0, 63, 0, out_tlv),
+       SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8983_LOUT2_SPK_VOLUME_CTRL,
+                    WM8983_ROUT2_SPK_VOLUME_CTRL, 7, 1, 0),
+       SOC_DOUBLE_R("Speaker Switch", WM8983_LOUT2_SPK_VOLUME_CTRL,
+                    WM8983_ROUT2_SPK_VOLUME_CTRL, 6, 1, 1),
+
+       SOC_SINGLE("OUT3 Switch", WM8983_OUT3_MIXER_CTRL,
+                  6, 1, 1),
+
+       SOC_SINGLE("OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+                  6, 1, 1),
+
+       SOC_SINGLE("High Pass Filter Switch", WM8983_ADC_CONTROL, 8, 1, 0),
+       SOC_ENUM("High Pass Filter Mode", filter_mode),
+       SOC_SINGLE("High Pass Filter Cutoff", WM8983_ADC_CONTROL, 4, 7, 0),
+
+       SOC_DOUBLE_R_TLV("Aux Bypass Volume",
+                        WM8983_LEFT_MIXER_CTRL, WM8983_RIGHT_MIXER_CTRL, 6, 7, 0,
+                        aux_tlv),
+
+       SOC_DOUBLE_R_TLV("Input PGA Bypass Volume",
+                        WM8983_LEFT_MIXER_CTRL, WM8983_RIGHT_MIXER_CTRL, 2, 7, 0,
+                        bypass_tlv),
+
+       SOC_ENUM_EXT("Equalizer Function", eqmode, eqmode_get, eqmode_put),
+       SOC_ENUM("EQ1 Cutoff", eq1_cutoff),
+       SOC_SINGLE_TLV("EQ1 Volume", WM8983_EQ1_LOW_SHELF,  0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ2 Bandwith", eq2_bw),
+       SOC_ENUM("EQ2 Cutoff", eq2_cutoff),
+       SOC_SINGLE_TLV("EQ2 Volume", WM8983_EQ2_PEAK_1, 0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ3 Bandwith", eq3_bw),
+       SOC_ENUM("EQ3 Cutoff", eq3_cutoff),
+       SOC_SINGLE_TLV("EQ3 Volume", WM8983_EQ3_PEAK_2, 0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ4 Bandwith", eq4_bw),
+       SOC_ENUM("EQ4 Cutoff", eq4_cutoff),
+       SOC_SINGLE_TLV("EQ4 Volume", WM8983_EQ4_PEAK_3, 0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ5 Cutoff", eq5_cutoff),
+       SOC_SINGLE_TLV("EQ5 Volume", WM8983_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv),
+
+       SOC_ENUM("3D Depth", depth_3d),
+
+       SOC_ENUM("Speaker Mode", speaker_mode)
+};
+
+static const struct snd_kcontrol_new left_out_mixer[] = {
+       SOC_DAPM_SINGLE("Line Switch", WM8983_LEFT_MIXER_CTRL, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Switch", WM8983_LEFT_MIXER_CTRL, 5, 1, 0),
+       SOC_DAPM_SINGLE("PCM Switch", WM8983_LEFT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_out_mixer[] = {
+       SOC_DAPM_SINGLE("Line Switch", WM8983_RIGHT_MIXER_CTRL, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Switch", WM8983_RIGHT_MIXER_CTRL, 5, 1, 0),
+       SOC_DAPM_SINGLE("PCM Switch", WM8983_RIGHT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer[] = {
+       SOC_DAPM_SINGLE("L2 Switch", WM8983_INPUT_CTRL, 2, 1, 0),
+       SOC_DAPM_SINGLE("MicN Switch", WM8983_INPUT_CTRL, 1, 1, 0),
+       SOC_DAPM_SINGLE("MicP Switch", WM8983_INPUT_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer[] = {
+       SOC_DAPM_SINGLE("R2 Switch", WM8983_INPUT_CTRL, 6, 1, 0),
+       SOC_DAPM_SINGLE("MicN Switch", WM8983_INPUT_CTRL, 5, 1, 0),
+       SOC_DAPM_SINGLE("MicP Switch", WM8983_INPUT_CTRL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_boost_mixer[] = {
+       SOC_DAPM_SINGLE_TLV("L2 Volume", WM8983_LEFT_ADC_BOOST_CTRL,
+                           4, 7, 0, boost_tlv),
+       SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8983_LEFT_ADC_BOOST_CTRL,
+                           0, 7, 0, boost_tlv)
+};
+
+static const struct snd_kcontrol_new out3_mixer[] = {
+       SOC_DAPM_SINGLE("LMIX2OUT3 Switch", WM8983_OUT3_MIXER_CTRL,
+                       1, 1, 0),
+       SOC_DAPM_SINGLE("LDAC2OUT3 Switch", WM8983_OUT3_MIXER_CTRL,
+                       0, 1, 0),
+};
+
+static const struct snd_kcontrol_new out4_mixer[] = {
+       SOC_DAPM_SINGLE("LMIX2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+                       4, 1, 0),
+       SOC_DAPM_SINGLE("RMIX2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+                       1, 1, 0),
+       SOC_DAPM_SINGLE("LDAC2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+                       3, 1, 0),
+       SOC_DAPM_SINGLE("RDAC2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+                       0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_boost_mixer[] = {
+       SOC_DAPM_SINGLE_TLV("R2 Volume", WM8983_RIGHT_ADC_BOOST_CTRL,
+                           4, 7, 0, boost_tlv),
+       SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8983_RIGHT_ADC_BOOST_CTRL,
+                           0, 7, 0, boost_tlv)
+};
+
+static const struct snd_soc_dapm_widget wm8983_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8983_POWER_MANAGEMENT_3,
+                        0, 0),
+       SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8983_POWER_MANAGEMENT_3,
+                        1, 0),
+       SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8983_POWER_MANAGEMENT_2,
+                        0, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8983_POWER_MANAGEMENT_2,
+                        1, 0),
+
+       SND_SOC_DAPM_MIXER("Left Output Mixer", WM8983_POWER_MANAGEMENT_3,
+                          2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)),
+       SND_SOC_DAPM_MIXER("Right Output Mixer", WM8983_POWER_MANAGEMENT_3,
+                          3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)),
+
+       SND_SOC_DAPM_MIXER("Left Input Mixer", WM8983_POWER_MANAGEMENT_2,
+                          2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)),
+       SND_SOC_DAPM_MIXER("Right Input Mixer", WM8983_POWER_MANAGEMENT_2,
+                          3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)),
+
+       SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8983_POWER_MANAGEMENT_2,
+                          4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)),
+       SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8983_POWER_MANAGEMENT_2,
+                          5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)),
+
+       SND_SOC_DAPM_MIXER("OUT3 Mixer", WM8983_POWER_MANAGEMENT_1,
+                          6, 0, out3_mixer, ARRAY_SIZE(out3_mixer)),
+
+       SND_SOC_DAPM_MIXER("OUT4 Mixer", WM8983_POWER_MANAGEMENT_1,
+                          7, 0, out4_mixer, ARRAY_SIZE(out4_mixer)),
+
+       SND_SOC_DAPM_PGA("Left Capture PGA", WM8983_LEFT_INP_PGA_GAIN_CTRL,
+                        6, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Capture PGA", WM8983_RIGHT_INP_PGA_GAIN_CTRL,
+                        6, 1, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Left Headphone Out", WM8983_POWER_MANAGEMENT_2,
+                        7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Headphone Out", WM8983_POWER_MANAGEMENT_2,
+                        8, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Left Speaker Out", WM8983_POWER_MANAGEMENT_3,
+                        5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Speaker Out", WM8983_POWER_MANAGEMENT_3,
+                        6, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("OUT3 Out", WM8983_POWER_MANAGEMENT_3,
+                        7, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("OUT4 Out", WM8983_POWER_MANAGEMENT_3,
+                        8, 0, NULL, 0),
+
+       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8983_POWER_MANAGEMENT_1, 4, 0),
+
+       SND_SOC_DAPM_INPUT("LIN"),
+       SND_SOC_DAPM_INPUT("LIP"),
+       SND_SOC_DAPM_INPUT("RIN"),
+       SND_SOC_DAPM_INPUT("RIP"),
+       SND_SOC_DAPM_INPUT("AUXL"),
+       SND_SOC_DAPM_INPUT("AUXR"),
+       SND_SOC_DAPM_INPUT("L2"),
+       SND_SOC_DAPM_INPUT("R2"),
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("SPKL"),
+       SND_SOC_DAPM_OUTPUT("SPKR"),
+       SND_SOC_DAPM_OUTPUT("OUT3"),
+       SND_SOC_DAPM_OUTPUT("OUT4")
+};
+
+static const struct snd_soc_dapm_route wm8983_audio_map[] = {
+       { "OUT3 Mixer", "LMIX2OUT3 Switch", "Left Output Mixer" },
+       { "OUT3 Mixer", "LDAC2OUT3 Switch", "Left DAC" },
+
+       { "OUT3 Out", NULL, "OUT3 Mixer" },
+       { "OUT3", NULL, "OUT3 Out" },
+
+       { "OUT4 Mixer", "LMIX2OUT4 Switch", "Left Output Mixer" },
+       { "OUT4 Mixer", "RMIX2OUT4 Switch", "Right Output Mixer" },
+       { "OUT4 Mixer", "LDAC2OUT4 Switch", "Left DAC" },
+       { "OUT4 Mixer", "RDAC2OUT4 Switch", "Right DAC" },
+
+       { "OUT4 Out", NULL, "OUT4 Mixer" },
+       { "OUT4", NULL, "OUT4 Out" },
+
+       { "Right Output Mixer", "PCM Switch", "Right DAC" },
+       { "Right Output Mixer", "Aux Switch", "AUXR" },
+       { "Right Output Mixer", "Line Switch", "Right Boost Mixer" },
+
+       { "Left Output Mixer", "PCM Switch", "Left DAC" },
+       { "Left Output Mixer", "Aux Switch", "AUXL" },
+       { "Left Output Mixer", "Line Switch", "Left Boost Mixer" },
+
+       { "Right Headphone Out", NULL, "Right Output Mixer" },
+       { "HPR", NULL, "Right Headphone Out" },
+
+       { "Left Headphone Out", NULL, "Left Output Mixer" },
+       { "HPL", NULL, "Left Headphone Out" },
+
+       { "Right Speaker Out", NULL, "Right Output Mixer" },
+       { "SPKR", NULL, "Right Speaker Out" },
+
+       { "Left Speaker Out", NULL, "Left Output Mixer" },
+       { "SPKL", NULL, "Left Speaker Out" },
+
+       { "Right ADC", NULL, "Right Boost Mixer" },
+
+       { "Right Boost Mixer", "AUXR Volume", "AUXR" },
+       { "Right Boost Mixer", NULL, "Right Capture PGA" },
+       { "Right Boost Mixer", "R2 Volume", "R2" },
+
+       { "Left ADC", NULL, "Left Boost Mixer" },
+
+       { "Left Boost Mixer", "AUXL Volume", "AUXL" },
+       { "Left Boost Mixer", NULL, "Left Capture PGA" },
+       { "Left Boost Mixer", "L2 Volume", "L2" },
+
+       { "Right Capture PGA", NULL, "Right Input Mixer" },
+       { "Left Capture PGA", NULL, "Left Input Mixer" },
+
+       { "Right Input Mixer", "R2 Switch", "R2" },
+       { "Right Input Mixer", "MicN Switch", "RIN" },
+       { "Right Input Mixer", "MicP Switch", "RIP" },
+
+       { "Left Input Mixer", "L2 Switch", "L2" },
+       { "Left Input Mixer", "MicN Switch", "LIN" },
+       { "Left Input Mixer", "MicP Switch", "LIP" },
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg;
+
+       reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF);
+       if (reg & WM8983_EQ3DMODE)
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int regpwr2, regpwr3;
+       unsigned int reg_eq;
+
+       if (ucontrol->value.integer.value[0] != 0
+           && ucontrol->value.integer.value[0] != 1)
+               return -EINVAL;
+
+       reg_eq = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF);
+       switch ((reg_eq & WM8983_EQ3DMODE) >> WM8983_EQ3DMODE_SHIFT) {
+       case 0:
+               if (!ucontrol->value.integer.value[0])
+                       return 0;
+               break;
+       case 1:
+               if (ucontrol->value.integer.value[0])
+                       return 0;
+               break;
+       }
+
+       regpwr2 = snd_soc_read(codec, WM8983_POWER_MANAGEMENT_2);
+       regpwr3 = snd_soc_read(codec, WM8983_POWER_MANAGEMENT_3);
+       /* disable the DACs and ADCs */
+       snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_2,
+                           WM8983_ADCENR_MASK | WM8983_ADCENL_MASK, 0);
+       snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_3,
+                           WM8983_DACENR_MASK | WM8983_DACENL_MASK, 0);
+       /* set the desired eqmode */
+       snd_soc_update_bits(codec, WM8983_EQ1_LOW_SHELF,
+                           WM8983_EQ3DMODE_MASK,
+                           ucontrol->value.integer.value[0]
+                           << WM8983_EQ3DMODE_SHIFT);
+       /* restore DAC/ADC configuration */
+       snd_soc_write(codec, WM8983_POWER_MANAGEMENT_2, regpwr2);
+       snd_soc_write(codec, WM8983_POWER_MANAGEMENT_3, regpwr3);
+       return 0;
+}
+
+static int wm8983_readable(struct snd_soc_codec *codec, unsigned int reg)
+{
+       if (reg > WM8983_MAX_REGISTER)
+               return 0;
+
+       return wm8983_access_masks[reg].read != 0;
+}
+
+static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       return snd_soc_update_bits(codec, WM8983_DAC_CONTROL,
+                                  WM8983_SOFTMUTE_MASK,
+                                  !!mute << WM8983_SOFTMUTE_SHIFT);
+}
+
+static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 format, master, bcp, lrp;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               format = 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               format = 0x0;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               format = 0x1;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               format = 0x3;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown dai format\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE,
+                           WM8983_FMT_MASK, format << WM8983_FMT_SHIFT);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               master = 0;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown master/slave configuration\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+                           WM8983_MS_MASK, master << WM8983_MS_SHIFT);
+
+       /* FIXME: We don't currently support DSP A/B modes */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               dev_err(dai->dev, "DSP A/B modes are not supported\n");
+               return -EINVAL;
+       default:
+               break;
+       }
+
+       bcp = lrp = 0;
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               bcp = lrp = 1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               bcp = 1;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               lrp = 1;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown polarity configuration\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE,
+                           WM8983_LRCP_MASK, lrp << WM8983_LRCP_SHIFT);
+       snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE,
+                           WM8983_BCP_MASK, bcp << WM8983_BCP_SHIFT);
+       return 0;
+}
+
+static int wm8983_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       int i;
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);
+       u16 blen, srate_idx;
+       u32 tmp;
+       int srate_best;
+       int ret;
+
+       ret = snd_soc_params_to_bclk(params);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to convert params to bclk: %d\n", ret);
+               return ret;
+       }
+
+       wm8983->bclk = ret;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               blen = 0x0;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               blen = 0x1;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               blen = 0x2;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               blen = 0x3;
+               break;
+       default:
+               dev_err(dai->dev, "Unsupported word length %u\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE,
+                           WM8983_WL_MASK, blen << WM8983_WL_SHIFT);
+
+       /*
+        * match to the nearest possible sample rate and rely
+        * on the array index to configure the SR register
+        */
+       srate_idx = 0;
+       srate_best = abs(srates[0] - params_rate(params));
+       for (i = 1; i < ARRAY_SIZE(srates); ++i) {
+               if (abs(srates[i] - params_rate(params)) >= srate_best)
+                       continue;
+               srate_idx = i;
+               srate_best = abs(srates[i] - params_rate(params));
+       }
+
+       dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
+       snd_soc_update_bits(codec, WM8983_ADDITIONAL_CONTROL,
+                           WM8983_SR_MASK, srate_idx << WM8983_SR_SHIFT);
+
+       dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8983->bclk);
+       dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8983->sysclk);
+
+       for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) {
+               if (wm8983->sysclk / params_rate(params)
+                   == fs_ratios[i].ratio)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(fs_ratios)) {
+               dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n",
+                       wm8983->sysclk, params_rate(params));
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
+       snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+                           WM8983_MCLKDIV_MASK, i << WM8983_MCLKDIV_SHIFT);
+
+       /* select the appropriate bclk divider */
+       tmp = (wm8983->sysclk / fs_ratios[i].div) * 10;
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) {
+               if (wm8983->bclk == tmp / bclk_divs[i])
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(bclk_divs)) {
+               dev_err(dai->dev, "No matching BCLK divider found\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "BCLK div = %d\n", i);
+       snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+                           WM8983_BCLKDIV_MASK, i << WM8983_BCLKDIV_SHIFT);
+
+       return 0;
+}
+
+struct pll_div {
+       u32 div2:1;
+       u32 n:4;
+       u32 k:24;
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 24) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+                      unsigned int source)
+{
+       u64 Kpart;
+       unsigned long int K, Ndiv, Nmod;
+
+       pll_div->div2 = 0;
+       Ndiv = target / source;
+       if (Ndiv < 6) {
+               source >>= 1;
+               pll_div->div2 = 1;
+               Ndiv = target / source;
+       }
+
+       if (Ndiv < 6 || Ndiv > 12) {
+               printk(KERN_ERR "%s: WM8983 N value is not within"
+                      " the recommended range: %lu\n", __func__, Ndiv);
+               return -EINVAL;
+       }
+       pll_div->n = Ndiv;
+
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xffffffff;
+       if ((K % 10) >= 5)
+               K += 5;
+       K /= 10;
+       pll_div->k = K;
+       return 0;
+}
+
+static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id,
+                         int source, unsigned int freq_in,
+                         unsigned int freq_out)
+{
+       int ret;
+       struct snd_soc_codec *codec;
+       struct pll_div pll_div;
+
+       codec = dai->codec;
+       if (freq_in && freq_out) {
+               ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
+               if (ret)
+                       return ret;
+       }
+
+       /* disable the PLL before re-programming it */
+       snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                           WM8983_PLLEN_MASK, 0);
+
+       if (!freq_in || !freq_out)
+               return 0;
+
+       /* set PLLN and PRESCALE */
+       snd_soc_write(codec, WM8983_PLL_N,
+                     (pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT)
+                     | pll_div.n);
+       /* set PLLK */
+       snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff);
+       snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+       snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18));
+       /* enable the PLL */
+       snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                           WM8983_PLLEN_MASK, WM8983_PLLEN);
+       return 0;
+}
+
+static int wm8983_set_sysclk(struct snd_soc_dai *dai,
+                            int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case WM8983_CLKSRC_MCLK:
+               snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+                                   WM8983_CLKSEL_MASK, 0);
+               break;
+       case WM8983_CLKSRC_PLL:
+               snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+                                   WM8983_CLKSEL_MASK, WM8983_CLKSEL);
+               break;
+       default:
+               dev_err(dai->dev, "Unknown clock source: %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       wm8983->sysclk = freq;
+       return 0;
+}
+
+static int wm8983_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID at 100k */
+               snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                                   WM8983_VMIDSEL_MASK,
+                                   1 << WM8983_VMIDSEL_SHIFT);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = snd_soc_cache_sync(codec);
+                       if (ret < 0) {
+                               dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+                               return ret;
+                       }
+                       /* enable anti-pop features */
+                       snd_soc_update_bits(codec, WM8983_OUT4_TO_ADC,
+                                           WM8983_POBCTRL_MASK | WM8983_DELEN_MASK,
+                                           WM8983_POBCTRL | WM8983_DELEN);
+                       /* enable thermal shutdown */
+                       snd_soc_update_bits(codec, WM8983_OUTPUT_CTRL,
+                                           WM8983_TSDEN_MASK, WM8983_TSDEN);
+                       /* enable BIASEN */
+                       snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                                           WM8983_BIASEN_MASK, WM8983_BIASEN);
+                       /* VMID at 100k */
+                       snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                                           WM8983_VMIDSEL_MASK,
+                                           1 << WM8983_VMIDSEL_SHIFT);
+                       msleep(250);
+                       /* disable anti-pop features */
+                       snd_soc_update_bits(codec, WM8983_OUT4_TO_ADC,
+                                           WM8983_POBCTRL_MASK |
+                                           WM8983_DELEN_MASK, 0);
+               }
+
+               /* VMID at 500k */
+               snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                                   WM8983_VMIDSEL_MASK,
+                                   2 << WM8983_VMIDSEL_SHIFT);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* disable thermal shutdown */
+               snd_soc_update_bits(codec, WM8983_OUTPUT_CTRL,
+                                   WM8983_TSDEN_MASK, 0);
+               /* disable VMIDSEL and BIASEN */
+               snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                                   WM8983_VMIDSEL_MASK | WM8983_BIASEN_MASK,
+                                   0);
+               /* wait for VMID to discharge */
+               msleep(100);
+               snd_soc_write(codec, WM8983_POWER_MANAGEMENT_1, 0);
+               snd_soc_write(codec, WM8983_POWER_MANAGEMENT_2, 0);
+               snd_soc_write(codec, WM8983_POWER_MANAGEMENT_3, 0);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8983_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8983_resume(struct snd_soc_codec *codec)
+{
+       wm8983_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define wm8983_suspend NULL
+#define wm8983_resume NULL
+#endif
+
+static int wm8983_remove(struct snd_soc_codec *codec)
+{
+       wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8983_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8983->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0x8983);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
+       }
+
+       /* set the vol/gain update bits */
+       for (i = 0; i < ARRAY_SIZE(vol_update_regs); ++i)
+               snd_soc_update_bits(codec, vol_update_regs[i],
+                                   0x100, 0x100);
+
+       /* mute all outputs and set PGAs to minimum gain */
+       for (i = WM8983_LOUT1_HP_VOLUME_CTRL;
+            i <= WM8983_OUT4_MONO_MIX_CTRL; ++i)
+               snd_soc_update_bits(codec, i, 0x40, 0x40);
+
+       /* enable soft mute */
+       snd_soc_update_bits(codec, WM8983_DAC_CONTROL,
+                           WM8983_SOFTMUTE_MASK,
+                           WM8983_SOFTMUTE);
+
+       /* enable BIASCUT */
+       snd_soc_update_bits(codec, WM8983_BIAS_CTRL,
+                           WM8983_BIASCUT, WM8983_BIASCUT);
+       return 0;
+}
+
+static struct snd_soc_dai_ops wm8983_dai_ops = {
+       .digital_mute = wm8983_dac_mute,
+       .hw_params = wm8983_hw_params,
+       .set_fmt = wm8983_set_fmt,
+       .set_sysclk = wm8983_set_sysclk,
+       .set_pll = wm8983_set_pll
+};
+
+#define WM8983_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8983_dai = {
+       .name = "wm8983-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = WM8983_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = WM8983_FORMATS,
+       },
+       .ops = &wm8983_dai_ops,
+       .symmetric_rates = 1
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8983 = {
+       .probe = wm8983_probe,
+       .remove = wm8983_remove,
+       .suspend = wm8983_suspend,
+       .resume = wm8983_resume,
+       .set_bias_level = wm8983_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8983_reg_defs),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8983_reg_defs,
+       .controls = wm8983_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8983_snd_controls),
+       .dapm_widgets = wm8983_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8983_dapm_widgets),
+       .dapm_routes = wm8983_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wm8983_audio_map),
+       .readable_register = wm8983_readable
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8983_spi_probe(struct spi_device *spi)
+{
+       struct wm8983_priv *wm8983;
+       int ret;
+
+       wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL);
+       if (!wm8983)
+               return -ENOMEM;
+
+       wm8983->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8983);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                                    &soc_codec_dev_wm8983, &wm8983_dai, 1);
+       if (ret < 0)
+               kfree(wm8983);
+       return ret;
+}
+
+static int __devexit wm8983_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver wm8983_spi_driver = {
+       .driver = {
+               .name = "wm8983",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8983_spi_probe,
+       .remove = __devexit_p(wm8983_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8983_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8983_priv *wm8983;
+       int ret;
+
+       wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL);
+       if (!wm8983)
+               return -ENOMEM;
+
+       wm8983->control_type = SND_SOC_I2C;
+       i2c_set_clientdata(i2c, wm8983);
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8983, &wm8983_dai, 1);
+       if (ret < 0)
+               kfree(wm8983);
+       return ret;
+}
+
+static __devexit int wm8983_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id wm8983_i2c_id[] = {
+       { "wm8983", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8983_i2c_id);
+
+static struct i2c_driver wm8983_i2c_driver = {
+       .driver = {
+               .name = "wm8983",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8983_i2c_probe,
+       .remove = __devexit_p(wm8983_i2c_remove),
+       .id_table = wm8983_i2c_id
+};
+#endif
+
+static int __init wm8983_modinit(void)
+{
+       int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8983_i2c_driver);
+       if (ret) {
+               printk(KERN_ERR "Failed to register wm8983 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8983_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8983 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
+}
+module_init(wm8983_modinit);
+
+static void __exit wm8983_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8983_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8983_spi_driver);
+#endif
+}
+module_exit(wm8983_exit);
+
+MODULE_DESCRIPTION("ASoC WM8983 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8983.h b/sound/soc/codecs/wm8983.h
new file mode 100644 (file)
index 0000000..71ee619
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ * wm8983.h  --  WM8983 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8983_H
+#define _WM8983_H
+
+/*
+ * Register values.
+ */
+#define WM8983_SOFTWARE_RESET                   0x00
+#define WM8983_POWER_MANAGEMENT_1               0x01
+#define WM8983_POWER_MANAGEMENT_2               0x02
+#define WM8983_POWER_MANAGEMENT_3               0x03
+#define WM8983_AUDIO_INTERFACE                  0x04
+#define WM8983_COMPANDING_CONTROL               0x05
+#define WM8983_CLOCK_GEN_CONTROL                0x06
+#define WM8983_ADDITIONAL_CONTROL               0x07
+#define WM8983_GPIO_CONTROL                     0x08
+#define WM8983_JACK_DETECT_CONTROL_1            0x09
+#define WM8983_DAC_CONTROL                      0x0A
+#define WM8983_LEFT_DAC_DIGITAL_VOL             0x0B
+#define WM8983_RIGHT_DAC_DIGITAL_VOL            0x0C
+#define WM8983_JACK_DETECT_CONTROL_2            0x0D
+#define WM8983_ADC_CONTROL                      0x0E
+#define WM8983_LEFT_ADC_DIGITAL_VOL             0x0F
+#define WM8983_RIGHT_ADC_DIGITAL_VOL            0x10
+#define WM8983_EQ1_LOW_SHELF                    0x12
+#define WM8983_EQ2_PEAK_1                       0x13
+#define WM8983_EQ3_PEAK_2                       0x14
+#define WM8983_EQ4_PEAK_3                       0x15
+#define WM8983_EQ5_HIGH_SHELF                   0x16
+#define WM8983_DAC_LIMITER_1                    0x18
+#define WM8983_DAC_LIMITER_2                    0x19
+#define WM8983_NOTCH_FILTER_1                   0x1B
+#define WM8983_NOTCH_FILTER_2                   0x1C
+#define WM8983_NOTCH_FILTER_3                   0x1D
+#define WM8983_NOTCH_FILTER_4                   0x1E
+#define WM8983_ALC_CONTROL_1                    0x20
+#define WM8983_ALC_CONTROL_2                    0x21
+#define WM8983_ALC_CONTROL_3                    0x22
+#define WM8983_NOISE_GATE                       0x23
+#define WM8983_PLL_N                            0x24
+#define WM8983_PLL_K_1                          0x25
+#define WM8983_PLL_K_2                          0x26
+#define WM8983_PLL_K_3                          0x27
+#define WM8983_3D_CONTROL                       0x29
+#define WM8983_OUT4_TO_ADC                      0x2A
+#define WM8983_BEEP_CONTROL                     0x2B
+#define WM8983_INPUT_CTRL                       0x2C
+#define WM8983_LEFT_INP_PGA_GAIN_CTRL           0x2D
+#define WM8983_RIGHT_INP_PGA_GAIN_CTRL          0x2E
+#define WM8983_LEFT_ADC_BOOST_CTRL              0x2F
+#define WM8983_RIGHT_ADC_BOOST_CTRL             0x30
+#define WM8983_OUTPUT_CTRL                      0x31
+#define WM8983_LEFT_MIXER_CTRL                  0x32
+#define WM8983_RIGHT_MIXER_CTRL                 0x33
+#define WM8983_LOUT1_HP_VOLUME_CTRL             0x34
+#define WM8983_ROUT1_HP_VOLUME_CTRL             0x35
+#define WM8983_LOUT2_SPK_VOLUME_CTRL            0x36
+#define WM8983_ROUT2_SPK_VOLUME_CTRL            0x37
+#define WM8983_OUT3_MIXER_CTRL                  0x38
+#define WM8983_OUT4_MONO_MIX_CTRL               0x39
+#define WM8983_BIAS_CTRL                        0x3D
+
+#define WM8983_REGISTER_COUNT                   59
+#define WM8983_MAX_REGISTER                     0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8983_SOFTWARE_RESET_MASK              0x01FF  /* SOFTWARE_RESET - [8:0] */
+#define WM8983_SOFTWARE_RESET_SHIFT                  0  /* SOFTWARE_RESET - [8:0] */
+#define WM8983_SOFTWARE_RESET_WIDTH                  9  /* SOFTWARE_RESET - [8:0] */
+
+/*
+ * R1 (0x01) - Power management 1
+ */
+#define WM8983_BUFDCOPEN                        0x0100  /* BUFDCOPEN */
+#define WM8983_BUFDCOPEN_MASK                   0x0100  /* BUFDCOPEN */
+#define WM8983_BUFDCOPEN_SHIFT                       8  /* BUFDCOPEN */
+#define WM8983_BUFDCOPEN_WIDTH                       1  /* BUFDCOPEN */
+#define WM8983_OUT4MIXEN                        0x0080  /* OUT4MIXEN */
+#define WM8983_OUT4MIXEN_MASK                   0x0080  /* OUT4MIXEN */
+#define WM8983_OUT4MIXEN_SHIFT                       7  /* OUT4MIXEN */
+#define WM8983_OUT4MIXEN_WIDTH                       1  /* OUT4MIXEN */
+#define WM8983_OUT3MIXEN                        0x0040  /* OUT3MIXEN */
+#define WM8983_OUT3MIXEN_MASK                   0x0040  /* OUT3MIXEN */
+#define WM8983_OUT3MIXEN_SHIFT                       6  /* OUT3MIXEN */
+#define WM8983_OUT3MIXEN_WIDTH                       1  /* OUT3MIXEN */
+#define WM8983_PLLEN                            0x0020  /* PLLEN */
+#define WM8983_PLLEN_MASK                       0x0020  /* PLLEN */
+#define WM8983_PLLEN_SHIFT                           5  /* PLLEN */
+#define WM8983_PLLEN_WIDTH                           1  /* PLLEN */
+#define WM8983_MICBEN                           0x0010  /* MICBEN */
+#define WM8983_MICBEN_MASK                      0x0010  /* MICBEN */
+#define WM8983_MICBEN_SHIFT                          4  /* MICBEN */
+#define WM8983_MICBEN_WIDTH                          1  /* MICBEN */
+#define WM8983_BIASEN                           0x0008  /* BIASEN */
+#define WM8983_BIASEN_MASK                      0x0008  /* BIASEN */
+#define WM8983_BIASEN_SHIFT                          3  /* BIASEN */
+#define WM8983_BIASEN_WIDTH                          1  /* BIASEN */
+#define WM8983_BUFIOEN                          0x0004  /* BUFIOEN */
+#define WM8983_BUFIOEN_MASK                     0x0004  /* BUFIOEN */
+#define WM8983_BUFIOEN_SHIFT                         2  /* BUFIOEN */
+#define WM8983_BUFIOEN_WIDTH                         1  /* BUFIOEN */
+#define WM8983_VMIDSEL_MASK                     0x0003  /* VMIDSEL - [1:0] */
+#define WM8983_VMIDSEL_SHIFT                         0  /* VMIDSEL - [1:0] */
+#define WM8983_VMIDSEL_WIDTH                         2  /* VMIDSEL - [1:0] */
+
+/*
+ * R2 (0x02) - Power management 2
+ */
+#define WM8983_ROUT1EN                          0x0100  /* ROUT1EN */
+#define WM8983_ROUT1EN_MASK                     0x0100  /* ROUT1EN */
+#define WM8983_ROUT1EN_SHIFT                         8  /* ROUT1EN */
+#define WM8983_ROUT1EN_WIDTH                         1  /* ROUT1EN */
+#define WM8983_LOUT1EN                          0x0080  /* LOUT1EN */
+#define WM8983_LOUT1EN_MASK                     0x0080  /* LOUT1EN */
+#define WM8983_LOUT1EN_SHIFT                         7  /* LOUT1EN */
+#define WM8983_LOUT1EN_WIDTH                         1  /* LOUT1EN */
+#define WM8983_SLEEP                            0x0040  /* SLEEP */
+#define WM8983_SLEEP_MASK                       0x0040  /* SLEEP */
+#define WM8983_SLEEP_SHIFT                           6  /* SLEEP */
+#define WM8983_SLEEP_WIDTH                           1  /* SLEEP */
+#define WM8983_BOOSTENR                         0x0020  /* BOOSTENR */
+#define WM8983_BOOSTENR_MASK                    0x0020  /* BOOSTENR */
+#define WM8983_BOOSTENR_SHIFT                        5  /* BOOSTENR */
+#define WM8983_BOOSTENR_WIDTH                        1  /* BOOSTENR */
+#define WM8983_BOOSTENL                         0x0010  /* BOOSTENL */
+#define WM8983_BOOSTENL_MASK                    0x0010  /* BOOSTENL */
+#define WM8983_BOOSTENL_SHIFT                        4  /* BOOSTENL */
+#define WM8983_BOOSTENL_WIDTH                        1  /* BOOSTENL */
+#define WM8983_INPGAENR                         0x0008  /* INPGAENR */
+#define WM8983_INPGAENR_MASK                    0x0008  /* INPGAENR */
+#define WM8983_INPGAENR_SHIFT                        3  /* INPGAENR */
+#define WM8983_INPGAENR_WIDTH                        1  /* INPGAENR */
+#define WM8983_INPPGAENL                        0x0004  /* INPPGAENL */
+#define WM8983_INPPGAENL_MASK                   0x0004  /* INPPGAENL */
+#define WM8983_INPPGAENL_SHIFT                       2  /* INPPGAENL */
+#define WM8983_INPPGAENL_WIDTH                       1  /* INPPGAENL */
+#define WM8983_ADCENR                           0x0002  /* ADCENR */
+#define WM8983_ADCENR_MASK                      0x0002  /* ADCENR */
+#define WM8983_ADCENR_SHIFT                          1  /* ADCENR */
+#define WM8983_ADCENR_WIDTH                          1  /* ADCENR */
+#define WM8983_ADCENL                           0x0001  /* ADCENL */
+#define WM8983_ADCENL_MASK                      0x0001  /* ADCENL */
+#define WM8983_ADCENL_SHIFT                          0  /* ADCENL */
+#define WM8983_ADCENL_WIDTH                          1  /* ADCENL */
+
+/*
+ * R3 (0x03) - Power management 3
+ */
+#define WM8983_OUT4EN                           0x0100  /* OUT4EN */
+#define WM8983_OUT4EN_MASK                      0x0100  /* OUT4EN */
+#define WM8983_OUT4EN_SHIFT                          8  /* OUT4EN */
+#define WM8983_OUT4EN_WIDTH                          1  /* OUT4EN */
+#define WM8983_OUT3EN                           0x0080  /* OUT3EN */
+#define WM8983_OUT3EN_MASK                      0x0080  /* OUT3EN */
+#define WM8983_OUT3EN_SHIFT                          7  /* OUT3EN */
+#define WM8983_OUT3EN_WIDTH                          1  /* OUT3EN */
+#define WM8983_LOUT2EN                          0x0040  /* LOUT2EN */
+#define WM8983_LOUT2EN_MASK                     0x0040  /* LOUT2EN */
+#define WM8983_LOUT2EN_SHIFT                         6  /* LOUT2EN */
+#define WM8983_LOUT2EN_WIDTH                         1  /* LOUT2EN */
+#define WM8983_ROUT2EN                          0x0020  /* ROUT2EN */
+#define WM8983_ROUT2EN_MASK                     0x0020  /* ROUT2EN */
+#define WM8983_ROUT2EN_SHIFT                         5  /* ROUT2EN */
+#define WM8983_ROUT2EN_WIDTH                         1  /* ROUT2EN */
+#define WM8983_RMIXEN                           0x0008  /* RMIXEN */
+#define WM8983_RMIXEN_MASK                      0x0008  /* RMIXEN */
+#define WM8983_RMIXEN_SHIFT                          3  /* RMIXEN */
+#define WM8983_RMIXEN_WIDTH                          1  /* RMIXEN */
+#define WM8983_LMIXEN                           0x0004  /* LMIXEN */
+#define WM8983_LMIXEN_MASK                      0x0004  /* LMIXEN */
+#define WM8983_LMIXEN_SHIFT                          2  /* LMIXEN */
+#define WM8983_LMIXEN_WIDTH                          1  /* LMIXEN */
+#define WM8983_DACENR                           0x0002  /* DACENR */
+#define WM8983_DACENR_MASK                      0x0002  /* DACENR */
+#define WM8983_DACENR_SHIFT                          1  /* DACENR */
+#define WM8983_DACENR_WIDTH                          1  /* DACENR */
+#define WM8983_DACENL                           0x0001  /* DACENL */
+#define WM8983_DACENL_MASK                      0x0001  /* DACENL */
+#define WM8983_DACENL_SHIFT                          0  /* DACENL */
+#define WM8983_DACENL_WIDTH                          1  /* DACENL */
+
+/*
+ * R4 (0x04) - Audio Interface
+ */
+#define WM8983_BCP                              0x0100  /* BCP */
+#define WM8983_BCP_MASK                         0x0100  /* BCP */
+#define WM8983_BCP_SHIFT                             8  /* BCP */
+#define WM8983_BCP_WIDTH                             1  /* BCP */
+#define WM8983_LRCP                             0x0080  /* LRCP */
+#define WM8983_LRCP_MASK                        0x0080  /* LRCP */
+#define WM8983_LRCP_SHIFT                            7  /* LRCP */
+#define WM8983_LRCP_WIDTH                            1  /* LRCP */
+#define WM8983_WL_MASK                          0x0060  /* WL - [6:5] */
+#define WM8983_WL_SHIFT                              5  /* WL - [6:5] */
+#define WM8983_WL_WIDTH                              2  /* WL - [6:5] */
+#define WM8983_FMT_MASK                         0x0018  /* FMT - [4:3] */
+#define WM8983_FMT_SHIFT                             3  /* FMT - [4:3] */
+#define WM8983_FMT_WIDTH                             2  /* FMT - [4:3] */
+#define WM8983_DLRSWAP                          0x0004  /* DLRSWAP */
+#define WM8983_DLRSWAP_MASK                     0x0004  /* DLRSWAP */
+#define WM8983_DLRSWAP_SHIFT                         2  /* DLRSWAP */
+#define WM8983_DLRSWAP_WIDTH                         1  /* DLRSWAP */
+#define WM8983_ALRSWAP                          0x0002  /* ALRSWAP */
+#define WM8983_ALRSWAP_MASK                     0x0002  /* ALRSWAP */
+#define WM8983_ALRSWAP_SHIFT                         1  /* ALRSWAP */
+#define WM8983_ALRSWAP_WIDTH                         1  /* ALRSWAP */
+#define WM8983_MONO                             0x0001  /* MONO */
+#define WM8983_MONO_MASK                        0x0001  /* MONO */
+#define WM8983_MONO_SHIFT                            0  /* MONO */
+#define WM8983_MONO_WIDTH                            1  /* MONO */
+
+/*
+ * R5 (0x05) - Companding control
+ */
+#define WM8983_WL8                              0x0020  /* WL8 */
+#define WM8983_WL8_MASK                         0x0020  /* WL8 */
+#define WM8983_WL8_SHIFT                             5  /* WL8 */
+#define WM8983_WL8_WIDTH                             1  /* WL8 */
+#define WM8983_DAC_COMP_MASK                    0x0018  /* DAC_COMP - [4:3] */
+#define WM8983_DAC_COMP_SHIFT                        3  /* DAC_COMP - [4:3] */
+#define WM8983_DAC_COMP_WIDTH                        2  /* DAC_COMP - [4:3] */
+#define WM8983_ADC_COMP_MASK                    0x0006  /* ADC_COMP - [2:1] */
+#define WM8983_ADC_COMP_SHIFT                        1  /* ADC_COMP - [2:1] */
+#define WM8983_ADC_COMP_WIDTH                        2  /* ADC_COMP - [2:1] */
+#define WM8983_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8983_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8983_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8983_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clock Gen control
+ */
+#define WM8983_CLKSEL                           0x0100  /* CLKSEL */
+#define WM8983_CLKSEL_MASK                      0x0100  /* CLKSEL */
+#define WM8983_CLKSEL_SHIFT                          8  /* CLKSEL */
+#define WM8983_CLKSEL_WIDTH                          1  /* CLKSEL */
+#define WM8983_MCLKDIV_MASK                     0x00E0  /* MCLKDIV - [7:5] */
+#define WM8983_MCLKDIV_SHIFT                         5  /* MCLKDIV - [7:5] */
+#define WM8983_MCLKDIV_WIDTH                         3  /* MCLKDIV - [7:5] */
+#define WM8983_BCLKDIV_MASK                     0x001C  /* BCLKDIV - [4:2] */
+#define WM8983_BCLKDIV_SHIFT                         2  /* BCLKDIV - [4:2] */
+#define WM8983_BCLKDIV_WIDTH                         3  /* BCLKDIV - [4:2] */
+#define WM8983_MS                               0x0001  /* MS */
+#define WM8983_MS_MASK                          0x0001  /* MS */
+#define WM8983_MS_SHIFT                              0  /* MS */
+#define WM8983_MS_WIDTH                              1  /* MS */
+
+/*
+ * R7 (0x07) - Additional control
+ */
+#define WM8983_SR_MASK                          0x000E  /* SR - [3:1] */
+#define WM8983_SR_SHIFT                              1  /* SR - [3:1] */
+#define WM8983_SR_WIDTH                              3  /* SR - [3:1] */
+#define WM8983_SLOWCLKEN                        0x0001  /* SLOWCLKEN */
+#define WM8983_SLOWCLKEN_MASK                   0x0001  /* SLOWCLKEN */
+#define WM8983_SLOWCLKEN_SHIFT                       0  /* SLOWCLKEN */
+#define WM8983_SLOWCLKEN_WIDTH                       1  /* SLOWCLKEN */
+
+/*
+ * R8 (0x08) - GPIO Control
+ */
+#define WM8983_OPCLKDIV_MASK                    0x0030  /* OPCLKDIV - [5:4] */
+#define WM8983_OPCLKDIV_SHIFT                        4  /* OPCLKDIV - [5:4] */
+#define WM8983_OPCLKDIV_WIDTH                        2  /* OPCLKDIV - [5:4] */
+#define WM8983_GPIO1POL                         0x0008  /* GPIO1POL */
+#define WM8983_GPIO1POL_MASK                    0x0008  /* GPIO1POL */
+#define WM8983_GPIO1POL_SHIFT                        3  /* GPIO1POL */
+#define WM8983_GPIO1POL_WIDTH                        1  /* GPIO1POL */
+#define WM8983_GPIO1SEL_MASK                    0x0007  /* GPIO1SEL - [2:0] */
+#define WM8983_GPIO1SEL_SHIFT                        0  /* GPIO1SEL - [2:0] */
+#define WM8983_GPIO1SEL_WIDTH                        3  /* GPIO1SEL - [2:0] */
+
+/*
+ * R9 (0x09) - Jack Detect Control 1
+ */
+#define WM8983_JD_VMID1                         0x0100  /* JD_VMID1 */
+#define WM8983_JD_VMID1_MASK                    0x0100  /* JD_VMID1 */
+#define WM8983_JD_VMID1_SHIFT                        8  /* JD_VMID1 */
+#define WM8983_JD_VMID1_WIDTH                        1  /* JD_VMID1 */
+#define WM8983_JD_VMID0                         0x0080  /* JD_VMID0 */
+#define WM8983_JD_VMID0_MASK                    0x0080  /* JD_VMID0 */
+#define WM8983_JD_VMID0_SHIFT                        7  /* JD_VMID0 */
+#define WM8983_JD_VMID0_WIDTH                        1  /* JD_VMID0 */
+#define WM8983_JD_EN                            0x0040  /* JD_EN */
+#define WM8983_JD_EN_MASK                       0x0040  /* JD_EN */
+#define WM8983_JD_EN_SHIFT                           6  /* JD_EN */
+#define WM8983_JD_EN_WIDTH                           1  /* JD_EN */
+#define WM8983_JD_SEL_MASK                      0x0030  /* JD_SEL - [5:4] */
+#define WM8983_JD_SEL_SHIFT                          4  /* JD_SEL - [5:4] */
+#define WM8983_JD_SEL_WIDTH                          2  /* JD_SEL - [5:4] */
+
+/*
+ * R10 (0x0A) - DAC Control
+ */
+#define WM8983_SOFTMUTE                         0x0040  /* SOFTMUTE */
+#define WM8983_SOFTMUTE_MASK                    0x0040  /* SOFTMUTE */
+#define WM8983_SOFTMUTE_SHIFT                        6  /* SOFTMUTE */
+#define WM8983_SOFTMUTE_WIDTH                        1  /* SOFTMUTE */
+#define WM8983_DACOSR128                        0x0008  /* DACOSR128 */
+#define WM8983_DACOSR128_MASK                   0x0008  /* DACOSR128 */
+#define WM8983_DACOSR128_SHIFT                       3  /* DACOSR128 */
+#define WM8983_DACOSR128_WIDTH                       1  /* DACOSR128 */
+#define WM8983_AMUTE                            0x0004  /* AMUTE */
+#define WM8983_AMUTE_MASK                       0x0004  /* AMUTE */
+#define WM8983_AMUTE_SHIFT                           2  /* AMUTE */
+#define WM8983_AMUTE_WIDTH                           1  /* AMUTE */
+#define WM8983_DACRPOL                          0x0002  /* DACRPOL */
+#define WM8983_DACRPOL_MASK                     0x0002  /* DACRPOL */
+#define WM8983_DACRPOL_SHIFT                         1  /* DACRPOL */
+#define WM8983_DACRPOL_WIDTH                         1  /* DACRPOL */
+#define WM8983_DACLPOL                          0x0001  /* DACLPOL */
+#define WM8983_DACLPOL_MASK                     0x0001  /* DACLPOL */
+#define WM8983_DACLPOL_SHIFT                         0  /* DACLPOL */
+#define WM8983_DACLPOL_WIDTH                         1  /* DACLPOL */
+
+/*
+ * R11 (0x0B) - Left DAC digital Vol
+ */
+#define WM8983_DACVU                            0x0100  /* DACVU */
+#define WM8983_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8983_DACVU_SHIFT                           8  /* DACVU */
+#define WM8983_DACVU_WIDTH                           1  /* DACVU */
+#define WM8983_DACLVOL_MASK                     0x00FF  /* DACLVOL - [7:0] */
+#define WM8983_DACLVOL_SHIFT                         0  /* DACLVOL - [7:0] */
+#define WM8983_DACLVOL_WIDTH                         8  /* DACLVOL - [7:0] */
+
+/*
+ * R12 (0x0C) - Right DAC digital vol
+ */
+#define WM8983_DACVU                            0x0100  /* DACVU */
+#define WM8983_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8983_DACVU_SHIFT                           8  /* DACVU */
+#define WM8983_DACVU_WIDTH                           1  /* DACVU */
+#define WM8983_DACRVOL_MASK                     0x00FF  /* DACRVOL - [7:0] */
+#define WM8983_DACRVOL_SHIFT                         0  /* DACRVOL - [7:0] */
+#define WM8983_DACRVOL_WIDTH                         8  /* DACRVOL - [7:0] */
+
+/*
+ * R13 (0x0D) - Jack Detect Control 2
+ */
+#define WM8983_JD_EN1_MASK                      0x00F0  /* JD_EN1 - [7:4] */
+#define WM8983_JD_EN1_SHIFT                          4  /* JD_EN1 - [7:4] */
+#define WM8983_JD_EN1_WIDTH                          4  /* JD_EN1 - [7:4] */
+#define WM8983_JD_EN0_MASK                      0x000F  /* JD_EN0 - [3:0] */
+#define WM8983_JD_EN0_SHIFT                          0  /* JD_EN0 - [3:0] */
+#define WM8983_JD_EN0_WIDTH                          4  /* JD_EN0 - [3:0] */
+
+/*
+ * R14 (0x0E) - ADC Control
+ */
+#define WM8983_HPFEN                            0x0100  /* HPFEN */
+#define WM8983_HPFEN_MASK                       0x0100  /* HPFEN */
+#define WM8983_HPFEN_SHIFT                           8  /* HPFEN */
+#define WM8983_HPFEN_WIDTH                           1  /* HPFEN */
+#define WM8983_HPFAPP                           0x0080  /* HPFAPP */
+#define WM8983_HPFAPP_MASK                      0x0080  /* HPFAPP */
+#define WM8983_HPFAPP_SHIFT                          7  /* HPFAPP */
+#define WM8983_HPFAPP_WIDTH                          1  /* HPFAPP */
+#define WM8983_HPFCUT_MASK                      0x0070  /* HPFCUT - [6:4] */
+#define WM8983_HPFCUT_SHIFT                          4  /* HPFCUT - [6:4] */
+#define WM8983_HPFCUT_WIDTH                          3  /* HPFCUT - [6:4] */
+#define WM8983_ADCOSR128                        0x0008  /* ADCOSR128 */
+#define WM8983_ADCOSR128_MASK                   0x0008  /* ADCOSR128 */
+#define WM8983_ADCOSR128_SHIFT                       3  /* ADCOSR128 */
+#define WM8983_ADCOSR128_WIDTH                       1  /* ADCOSR128 */
+#define WM8983_ADCRPOL                          0x0002  /* ADCRPOL */
+#define WM8983_ADCRPOL_MASK                     0x0002  /* ADCRPOL */
+#define WM8983_ADCRPOL_SHIFT                         1  /* ADCRPOL */
+#define WM8983_ADCRPOL_WIDTH                         1  /* ADCRPOL */
+#define WM8983_ADCLPOL                          0x0001  /* ADCLPOL */
+#define WM8983_ADCLPOL_MASK                     0x0001  /* ADCLPOL */
+#define WM8983_ADCLPOL_SHIFT                         0  /* ADCLPOL */
+#define WM8983_ADCLPOL_WIDTH                         1  /* ADCLPOL */
+
+/*
+ * R15 (0x0F) - Left ADC Digital Vol
+ */
+#define WM8983_ADCVU                            0x0100  /* ADCVU */
+#define WM8983_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8983_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8983_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8983_ADCLVOL_MASK                     0x00FF  /* ADCLVOL - [7:0] */
+#define WM8983_ADCLVOL_SHIFT                         0  /* ADCLVOL - [7:0] */
+#define WM8983_ADCLVOL_WIDTH                         8  /* ADCLVOL - [7:0] */
+
+/*
+ * R16 (0x10) - Right ADC Digital Vol
+ */
+#define WM8983_ADCVU                            0x0100  /* ADCVU */
+#define WM8983_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8983_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8983_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8983_ADCRVOL_MASK                     0x00FF  /* ADCRVOL - [7:0] */
+#define WM8983_ADCRVOL_SHIFT                         0  /* ADCRVOL - [7:0] */
+#define WM8983_ADCRVOL_WIDTH                         8  /* ADCRVOL - [7:0] */
+
+/*
+ * R18 (0x12) - EQ1 - low shelf
+ */
+#define WM8983_EQ3DMODE                         0x0100  /* EQ3DMODE */
+#define WM8983_EQ3DMODE_MASK                    0x0100  /* EQ3DMODE */
+#define WM8983_EQ3DMODE_SHIFT                        8  /* EQ3DMODE */
+#define WM8983_EQ3DMODE_WIDTH                        1  /* EQ3DMODE */
+#define WM8983_EQ1C_MASK                        0x0060  /* EQ1C - [6:5] */
+#define WM8983_EQ1C_SHIFT                            5  /* EQ1C - [6:5] */
+#define WM8983_EQ1C_WIDTH                            2  /* EQ1C - [6:5] */
+#define WM8983_EQ1G_MASK                        0x001F  /* EQ1G - [4:0] */
+#define WM8983_EQ1G_SHIFT                            0  /* EQ1G - [4:0] */
+#define WM8983_EQ1G_WIDTH                            5  /* EQ1G - [4:0] */
+
+/*
+ * R19 (0x13) - EQ2 - peak 1
+ */
+#define WM8983_EQ2BW                            0x0100  /* EQ2BW */
+#define WM8983_EQ2BW_MASK                       0x0100  /* EQ2BW */
+#define WM8983_EQ2BW_SHIFT                           8  /* EQ2BW */
+#define WM8983_EQ2BW_WIDTH                           1  /* EQ2BW */
+#define WM8983_EQ2C_MASK                        0x0060  /* EQ2C - [6:5] */
+#define WM8983_EQ2C_SHIFT                            5  /* EQ2C - [6:5] */
+#define WM8983_EQ2C_WIDTH                            2  /* EQ2C - [6:5] */
+#define WM8983_EQ2G_MASK                        0x001F  /* EQ2G - [4:0] */
+#define WM8983_EQ2G_SHIFT                            0  /* EQ2G - [4:0] */
+#define WM8983_EQ2G_WIDTH                            5  /* EQ2G - [4:0] */
+
+/*
+ * R20 (0x14) - EQ3 - peak 2
+ */
+#define WM8983_EQ3BW                            0x0100  /* EQ3BW */
+#define WM8983_EQ3BW_MASK                       0x0100  /* EQ3BW */
+#define WM8983_EQ3BW_SHIFT                           8  /* EQ3BW */
+#define WM8983_EQ3BW_WIDTH                           1  /* EQ3BW */
+#define WM8983_EQ3C_MASK                        0x0060  /* EQ3C - [6:5] */
+#define WM8983_EQ3C_SHIFT                            5  /* EQ3C - [6:5] */
+#define WM8983_EQ3C_WIDTH                            2  /* EQ3C - [6:5] */
+#define WM8983_EQ3G_MASK                        0x001F  /* EQ3G - [4:0] */
+#define WM8983_EQ3G_SHIFT                            0  /* EQ3G - [4:0] */
+#define WM8983_EQ3G_WIDTH                            5  /* EQ3G - [4:0] */
+
+/*
+ * R21 (0x15) - EQ4 - peak 3
+ */
+#define WM8983_EQ4BW                            0x0100  /* EQ4BW */
+#define WM8983_EQ4BW_MASK                       0x0100  /* EQ4BW */
+#define WM8983_EQ4BW_SHIFT                           8  /* EQ4BW */
+#define WM8983_EQ4BW_WIDTH                           1  /* EQ4BW */
+#define WM8983_EQ4C_MASK                        0x0060  /* EQ4C - [6:5] */
+#define WM8983_EQ4C_SHIFT                            5  /* EQ4C - [6:5] */
+#define WM8983_EQ4C_WIDTH                            2  /* EQ4C - [6:5] */
+#define WM8983_EQ4G_MASK                        0x001F  /* EQ4G - [4:0] */
+#define WM8983_EQ4G_SHIFT                            0  /* EQ4G - [4:0] */
+#define WM8983_EQ4G_WIDTH                            5  /* EQ4G - [4:0] */
+
+/*
+ * R22 (0x16) - EQ5 - high shelf
+ */
+#define WM8983_EQ5C_MASK                        0x0060  /* EQ5C - [6:5] */
+#define WM8983_EQ5C_SHIFT                            5  /* EQ5C - [6:5] */
+#define WM8983_EQ5C_WIDTH                            2  /* EQ5C - [6:5] */
+#define WM8983_EQ5G_MASK                        0x001F  /* EQ5G - [4:0] */
+#define WM8983_EQ5G_SHIFT                            0  /* EQ5G - [4:0] */
+#define WM8983_EQ5G_WIDTH                            5  /* EQ5G - [4:0] */
+
+/*
+ * R24 (0x18) - DAC Limiter 1
+ */
+#define WM8983_LIMEN                            0x0100  /* LIMEN */
+#define WM8983_LIMEN_MASK                       0x0100  /* LIMEN */
+#define WM8983_LIMEN_SHIFT                           8  /* LIMEN */
+#define WM8983_LIMEN_WIDTH                           1  /* LIMEN */
+#define WM8983_LIMDCY_MASK                      0x00F0  /* LIMDCY - [7:4] */
+#define WM8983_LIMDCY_SHIFT                          4  /* LIMDCY - [7:4] */
+#define WM8983_LIMDCY_WIDTH                          4  /* LIMDCY - [7:4] */
+#define WM8983_LIMATK_MASK                      0x000F  /* LIMATK - [3:0] */
+#define WM8983_LIMATK_SHIFT                          0  /* LIMATK - [3:0] */
+#define WM8983_LIMATK_WIDTH                          4  /* LIMATK - [3:0] */
+
+/*
+ * R25 (0x19) - DAC Limiter 2
+ */
+#define WM8983_LIMLVL_MASK                      0x0070  /* LIMLVL - [6:4] */
+#define WM8983_LIMLVL_SHIFT                          4  /* LIMLVL - [6:4] */
+#define WM8983_LIMLVL_WIDTH                          3  /* LIMLVL - [6:4] */
+#define WM8983_LIMBOOST_MASK                    0x000F  /* LIMBOOST - [3:0] */
+#define WM8983_LIMBOOST_SHIFT                        0  /* LIMBOOST - [3:0] */
+#define WM8983_LIMBOOST_WIDTH                        4  /* LIMBOOST - [3:0] */
+
+/*
+ * R27 (0x1B) - Notch Filter 1
+ */
+#define WM8983_NFU                              0x0100  /* NFU */
+#define WM8983_NFU_MASK                         0x0100  /* NFU */
+#define WM8983_NFU_SHIFT                             8  /* NFU */
+#define WM8983_NFU_WIDTH                             1  /* NFU */
+#define WM8983_NFEN                             0x0080  /* NFEN */
+#define WM8983_NFEN_MASK                        0x0080  /* NFEN */
+#define WM8983_NFEN_SHIFT                            7  /* NFEN */
+#define WM8983_NFEN_WIDTH                            1  /* NFEN */
+#define WM8983_NFA0_13_7_MASK                   0x007F  /* NFA0(13:7) - [6:0] */
+#define WM8983_NFA0_13_7_SHIFT                       0  /* NFA0(13:7) - [6:0] */
+#define WM8983_NFA0_13_7_WIDTH                       7  /* NFA0(13:7) - [6:0] */
+
+/*
+ * R28 (0x1C) - Notch Filter 2
+ */
+#define WM8983_NFU                              0x0100  /* NFU */
+#define WM8983_NFU_MASK                         0x0100  /* NFU */
+#define WM8983_NFU_SHIFT                             8  /* NFU */
+#define WM8983_NFU_WIDTH                             1  /* NFU */
+#define WM8983_NFA0_6_0_MASK                    0x007F  /* NFA0(6:0) - [6:0] */
+#define WM8983_NFA0_6_0_SHIFT                        0  /* NFA0(6:0) - [6:0] */
+#define WM8983_NFA0_6_0_WIDTH                        7  /* NFA0(6:0) - [6:0] */
+
+/*
+ * R29 (0x1D) - Notch Filter 3
+ */
+#define WM8983_NFU                              0x0100  /* NFU */
+#define WM8983_NFU_MASK                         0x0100  /* NFU */
+#define WM8983_NFU_SHIFT                             8  /* NFU */
+#define WM8983_NFU_WIDTH                             1  /* NFU */
+#define WM8983_NFA1_13_7_MASK                   0x007F  /* NFA1(13:7) - [6:0] */
+#define WM8983_NFA1_13_7_SHIFT                       0  /* NFA1(13:7) - [6:0] */
+#define WM8983_NFA1_13_7_WIDTH                       7  /* NFA1(13:7) - [6:0] */
+
+/*
+ * R30 (0x1E) - Notch Filter 4
+ */
+#define WM8983_NFU                              0x0100  /* NFU */
+#define WM8983_NFU_MASK                         0x0100  /* NFU */
+#define WM8983_NFU_SHIFT                             8  /* NFU */
+#define WM8983_NFU_WIDTH                             1  /* NFU */
+#define WM8983_NFA1_6_0_MASK                    0x007F  /* NFA1(6:0) - [6:0] */
+#define WM8983_NFA1_6_0_SHIFT                        0  /* NFA1(6:0) - [6:0] */
+#define WM8983_NFA1_6_0_WIDTH                        7  /* NFA1(6:0) - [6:0] */
+
+/*
+ * R32 (0x20) - ALC control 1
+ */
+#define WM8983_ALCSEL_MASK                      0x0180  /* ALCSEL - [8:7] */
+#define WM8983_ALCSEL_SHIFT                          7  /* ALCSEL - [8:7] */
+#define WM8983_ALCSEL_WIDTH                          2  /* ALCSEL - [8:7] */
+#define WM8983_ALCMAX_MASK                      0x0038  /* ALCMAX - [5:3] */
+#define WM8983_ALCMAX_SHIFT                          3  /* ALCMAX - [5:3] */
+#define WM8983_ALCMAX_WIDTH                          3  /* ALCMAX - [5:3] */
+#define WM8983_ALCMIN_MASK                      0x0007  /* ALCMIN - [2:0] */
+#define WM8983_ALCMIN_SHIFT                          0  /* ALCMIN - [2:0] */
+#define WM8983_ALCMIN_WIDTH                          3  /* ALCMIN - [2:0] */
+
+/*
+ * R33 (0x21) - ALC control 2
+ */
+#define WM8983_ALCHLD_MASK                      0x00F0  /* ALCHLD - [7:4] */
+#define WM8983_ALCHLD_SHIFT                          4  /* ALCHLD - [7:4] */
+#define WM8983_ALCHLD_WIDTH                          4  /* ALCHLD - [7:4] */
+#define WM8983_ALCLVL_MASK                      0x000F  /* ALCLVL - [3:0] */
+#define WM8983_ALCLVL_SHIFT                          0  /* ALCLVL - [3:0] */
+#define WM8983_ALCLVL_WIDTH                          4  /* ALCLVL - [3:0] */
+
+/*
+ * R34 (0x22) - ALC control 3
+ */
+#define WM8983_ALCMODE                          0x0100  /* ALCMODE */
+#define WM8983_ALCMODE_MASK                     0x0100  /* ALCMODE */
+#define WM8983_ALCMODE_SHIFT                         8  /* ALCMODE */
+#define WM8983_ALCMODE_WIDTH                         1  /* ALCMODE */
+#define WM8983_ALCDCY_MASK                      0x00F0  /* ALCDCY - [7:4] */
+#define WM8983_ALCDCY_SHIFT                          4  /* ALCDCY - [7:4] */
+#define WM8983_ALCDCY_WIDTH                          4  /* ALCDCY - [7:4] */
+#define WM8983_ALCATK_MASK                      0x000F  /* ALCATK - [3:0] */
+#define WM8983_ALCATK_SHIFT                          0  /* ALCATK - [3:0] */
+#define WM8983_ALCATK_WIDTH                          4  /* ALCATK - [3:0] */
+
+/*
+ * R35 (0x23) - Noise Gate
+ */
+#define WM8983_NGEN                             0x0008  /* NGEN */
+#define WM8983_NGEN_MASK                        0x0008  /* NGEN */
+#define WM8983_NGEN_SHIFT                            3  /* NGEN */
+#define WM8983_NGEN_WIDTH                            1  /* NGEN */
+#define WM8983_NGTH_MASK                        0x0007  /* NGTH - [2:0] */
+#define WM8983_NGTH_SHIFT                            0  /* NGTH - [2:0] */
+#define WM8983_NGTH_WIDTH                            3  /* NGTH - [2:0] */
+
+/*
+ * R36 (0x24) - PLL N
+ */
+#define WM8983_PLL_PRESCALE                     0x0010  /* PLL_PRESCALE */
+#define WM8983_PLL_PRESCALE_MASK                0x0010  /* PLL_PRESCALE */
+#define WM8983_PLL_PRESCALE_SHIFT                    4  /* PLL_PRESCALE */
+#define WM8983_PLL_PRESCALE_WIDTH                    1  /* PLL_PRESCALE */
+#define WM8983_PLLN_MASK                        0x000F  /* PLLN - [3:0] */
+#define WM8983_PLLN_SHIFT                            0  /* PLLN - [3:0] */
+#define WM8983_PLLN_WIDTH                            4  /* PLLN - [3:0] */
+
+/*
+ * R37 (0x25) - PLL K 1
+ */
+#define WM8983_PLLK_23_18_MASK                  0x003F  /* PLLK(23:18) - [5:0] */
+#define WM8983_PLLK_23_18_SHIFT                      0  /* PLLK(23:18) - [5:0] */
+#define WM8983_PLLK_23_18_WIDTH                      6  /* PLLK(23:18) - [5:0] */
+
+/*
+ * R38 (0x26) - PLL K 2
+ */
+#define WM8983_PLLK_17_9_MASK                   0x01FF  /* PLLK(17:9) - [8:0] */
+#define WM8983_PLLK_17_9_SHIFT                       0  /* PLLK(17:9) - [8:0] */
+#define WM8983_PLLK_17_9_WIDTH                       9  /* PLLK(17:9) - [8:0] */
+
+/*
+ * R39 (0x27) - PLL K 3
+ */
+#define WM8983_PLLK_8_0_MASK                    0x01FF  /* PLLK(8:0) - [8:0] */
+#define WM8983_PLLK_8_0_SHIFT                        0  /* PLLK(8:0) - [8:0] */
+#define WM8983_PLLK_8_0_WIDTH                        9  /* PLLK(8:0) - [8:0] */
+
+/*
+ * R41 (0x29) - 3D control
+ */
+#define WM8983_DEPTH3D_MASK                     0x000F  /* DEPTH3D - [3:0] */
+#define WM8983_DEPTH3D_SHIFT                         0  /* DEPTH3D - [3:0] */
+#define WM8983_DEPTH3D_WIDTH                         4  /* DEPTH3D - [3:0] */
+
+/*
+ * R42 (0x2A) - OUT4 to ADC
+ */
+#define WM8983_OUT4_2ADCVOL_MASK                0x01C0  /* OUT4_2ADCVOL - [8:6] */
+#define WM8983_OUT4_2ADCVOL_SHIFT                    6  /* OUT4_2ADCVOL - [8:6] */
+#define WM8983_OUT4_2ADCVOL_WIDTH                    3  /* OUT4_2ADCVOL - [8:6] */
+#define WM8983_OUT4_2LNR                        0x0020  /* OUT4_2LNR */
+#define WM8983_OUT4_2LNR_MASK                   0x0020  /* OUT4_2LNR */
+#define WM8983_OUT4_2LNR_SHIFT                       5  /* OUT4_2LNR */
+#define WM8983_OUT4_2LNR_WIDTH                       1  /* OUT4_2LNR */
+#define WM8983_POBCTRL                          0x0004  /* POBCTRL */
+#define WM8983_POBCTRL_MASK                     0x0004  /* POBCTRL */
+#define WM8983_POBCTRL_SHIFT                         2  /* POBCTRL */
+#define WM8983_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8983_DELEN                            0x0002  /* DELEN */
+#define WM8983_DELEN_MASK                       0x0002  /* DELEN */
+#define WM8983_DELEN_SHIFT                           1  /* DELEN */
+#define WM8983_DELEN_WIDTH                           1  /* DELEN */
+#define WM8983_OUT1DEL                          0x0001  /* OUT1DEL */
+#define WM8983_OUT1DEL_MASK                     0x0001  /* OUT1DEL */
+#define WM8983_OUT1DEL_SHIFT                         0  /* OUT1DEL */
+#define WM8983_OUT1DEL_WIDTH                         1  /* OUT1DEL */
+
+/*
+ * R43 (0x2B) - Beep control
+ */
+#define WM8983_BYPL2RMIX                        0x0100  /* BYPL2RMIX */
+#define WM8983_BYPL2RMIX_MASK                   0x0100  /* BYPL2RMIX */
+#define WM8983_BYPL2RMIX_SHIFT                       8  /* BYPL2RMIX */
+#define WM8983_BYPL2RMIX_WIDTH                       1  /* BYPL2RMIX */
+#define WM8983_BYPR2LMIX                        0x0080  /* BYPR2LMIX */
+#define WM8983_BYPR2LMIX_MASK                   0x0080  /* BYPR2LMIX */
+#define WM8983_BYPR2LMIX_SHIFT                       7  /* BYPR2LMIX */
+#define WM8983_BYPR2LMIX_WIDTH                       1  /* BYPR2LMIX */
+#define WM8983_MUTERPGA2INV                     0x0020  /* MUTERPGA2INV */
+#define WM8983_MUTERPGA2INV_MASK                0x0020  /* MUTERPGA2INV */
+#define WM8983_MUTERPGA2INV_SHIFT                    5  /* MUTERPGA2INV */
+#define WM8983_MUTERPGA2INV_WIDTH                    1  /* MUTERPGA2INV */
+#define WM8983_INVROUT2                         0x0010  /* INVROUT2 */
+#define WM8983_INVROUT2_MASK                    0x0010  /* INVROUT2 */
+#define WM8983_INVROUT2_SHIFT                        4  /* INVROUT2 */
+#define WM8983_INVROUT2_WIDTH                        1  /* INVROUT2 */
+#define WM8983_BEEPVOL_MASK                     0x000E  /* BEEPVOL - [3:1] */
+#define WM8983_BEEPVOL_SHIFT                         1  /* BEEPVOL - [3:1] */
+#define WM8983_BEEPVOL_WIDTH                         3  /* BEEPVOL - [3:1] */
+#define WM8983_BEEPEN                           0x0001  /* BEEPEN */
+#define WM8983_BEEPEN_MASK                      0x0001  /* BEEPEN */
+#define WM8983_BEEPEN_SHIFT                          0  /* BEEPEN */
+#define WM8983_BEEPEN_WIDTH                          1  /* BEEPEN */
+
+/*
+ * R44 (0x2C) - Input ctrl
+ */
+#define WM8983_MBVSEL                           0x0100  /* MBVSEL */
+#define WM8983_MBVSEL_MASK                      0x0100  /* MBVSEL */
+#define WM8983_MBVSEL_SHIFT                          8  /* MBVSEL */
+#define WM8983_MBVSEL_WIDTH                          1  /* MBVSEL */
+#define WM8983_R2_2INPPGA                       0x0040  /* R2_2INPPGA */
+#define WM8983_R2_2INPPGA_MASK                  0x0040  /* R2_2INPPGA */
+#define WM8983_R2_2INPPGA_SHIFT                      6  /* R2_2INPPGA */
+#define WM8983_R2_2INPPGA_WIDTH                      1  /* R2_2INPPGA */
+#define WM8983_RIN2INPPGA                       0x0020  /* RIN2INPPGA */
+#define WM8983_RIN2INPPGA_MASK                  0x0020  /* RIN2INPPGA */
+#define WM8983_RIN2INPPGA_SHIFT                      5  /* RIN2INPPGA */
+#define WM8983_RIN2INPPGA_WIDTH                      1  /* RIN2INPPGA */
+#define WM8983_RIP2INPPGA                       0x0010  /* RIP2INPPGA */
+#define WM8983_RIP2INPPGA_MASK                  0x0010  /* RIP2INPPGA */
+#define WM8983_RIP2INPPGA_SHIFT                      4  /* RIP2INPPGA */
+#define WM8983_RIP2INPPGA_WIDTH                      1  /* RIP2INPPGA */
+#define WM8983_L2_2INPPGA                       0x0004  /* L2_2INPPGA */
+#define WM8983_L2_2INPPGA_MASK                  0x0004  /* L2_2INPPGA */
+#define WM8983_L2_2INPPGA_SHIFT                      2  /* L2_2INPPGA */
+#define WM8983_L2_2INPPGA_WIDTH                      1  /* L2_2INPPGA */
+#define WM8983_LIN2INPPGA                       0x0002  /* LIN2INPPGA */
+#define WM8983_LIN2INPPGA_MASK                  0x0002  /* LIN2INPPGA */
+#define WM8983_LIN2INPPGA_SHIFT                      1  /* LIN2INPPGA */
+#define WM8983_LIN2INPPGA_WIDTH                      1  /* LIN2INPPGA */
+#define WM8983_LIP2INPPGA                       0x0001  /* LIP2INPPGA */
+#define WM8983_LIP2INPPGA_MASK                  0x0001  /* LIP2INPPGA */
+#define WM8983_LIP2INPPGA_SHIFT                      0  /* LIP2INPPGA */
+#define WM8983_LIP2INPPGA_WIDTH                      1  /* LIP2INPPGA */
+
+/*
+ * R45 (0x2D) - Left INP PGA gain ctrl
+ */
+#define WM8983_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8983_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8983_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8983_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8983_INPPGAZCL                        0x0080  /* INPPGAZCL */
+#define WM8983_INPPGAZCL_MASK                   0x0080  /* INPPGAZCL */
+#define WM8983_INPPGAZCL_SHIFT                       7  /* INPPGAZCL */
+#define WM8983_INPPGAZCL_WIDTH                       1  /* INPPGAZCL */
+#define WM8983_INPPGAMUTEL                      0x0040  /* INPPGAMUTEL */
+#define WM8983_INPPGAMUTEL_MASK                 0x0040  /* INPPGAMUTEL */
+#define WM8983_INPPGAMUTEL_SHIFT                     6  /* INPPGAMUTEL */
+#define WM8983_INPPGAMUTEL_WIDTH                     1  /* INPPGAMUTEL */
+#define WM8983_INPPGAVOLL_MASK                  0x003F  /* INPPGAVOLL - [5:0] */
+#define WM8983_INPPGAVOLL_SHIFT                      0  /* INPPGAVOLL - [5:0] */
+#define WM8983_INPPGAVOLL_WIDTH                      6  /* INPPGAVOLL - [5:0] */
+
+/*
+ * R46 (0x2E) - Right INP PGA gain ctrl
+ */
+#define WM8983_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8983_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8983_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8983_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8983_INPPGAZCR                        0x0080  /* INPPGAZCR */
+#define WM8983_INPPGAZCR_MASK                   0x0080  /* INPPGAZCR */
+#define WM8983_INPPGAZCR_SHIFT                       7  /* INPPGAZCR */
+#define WM8983_INPPGAZCR_WIDTH                       1  /* INPPGAZCR */
+#define WM8983_INPPGAMUTER                      0x0040  /* INPPGAMUTER */
+#define WM8983_INPPGAMUTER_MASK                 0x0040  /* INPPGAMUTER */
+#define WM8983_INPPGAMUTER_SHIFT                     6  /* INPPGAMUTER */
+#define WM8983_INPPGAMUTER_WIDTH                     1  /* INPPGAMUTER */
+#define WM8983_INPPGAVOLR_MASK                  0x003F  /* INPPGAVOLR - [5:0] */
+#define WM8983_INPPGAVOLR_SHIFT                      0  /* INPPGAVOLR - [5:0] */
+#define WM8983_INPPGAVOLR_WIDTH                      6  /* INPPGAVOLR - [5:0] */
+
+/*
+ * R47 (0x2F) - Left ADC BOOST ctrl
+ */
+#define WM8983_PGABOOSTL                        0x0100  /* PGABOOSTL */
+#define WM8983_PGABOOSTL_MASK                   0x0100  /* PGABOOSTL */
+#define WM8983_PGABOOSTL_SHIFT                       8  /* PGABOOSTL */
+#define WM8983_PGABOOSTL_WIDTH                       1  /* PGABOOSTL */
+#define WM8983_L2_2BOOSTVOL_MASK                0x0070  /* L2_2BOOSTVOL - [6:4] */
+#define WM8983_L2_2BOOSTVOL_SHIFT                    4  /* L2_2BOOSTVOL - [6:4] */
+#define WM8983_L2_2BOOSTVOL_WIDTH                    3  /* L2_2BOOSTVOL - [6:4] */
+#define WM8983_AUXL2BOOSTVOL_MASK               0x0007  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8983_AUXL2BOOSTVOL_SHIFT                   0  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8983_AUXL2BOOSTVOL_WIDTH                   3  /* AUXL2BOOSTVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Right ADC BOOST ctrl
+ */
+#define WM8983_PGABOOSTR                        0x0100  /* PGABOOSTR */
+#define WM8983_PGABOOSTR_MASK                   0x0100  /* PGABOOSTR */
+#define WM8983_PGABOOSTR_SHIFT                       8  /* PGABOOSTR */
+#define WM8983_PGABOOSTR_WIDTH                       1  /* PGABOOSTR */
+#define WM8983_R2_2BOOSTVOL_MASK                0x0070  /* R2_2BOOSTVOL - [6:4] */
+#define WM8983_R2_2BOOSTVOL_SHIFT                    4  /* R2_2BOOSTVOL - [6:4] */
+#define WM8983_R2_2BOOSTVOL_WIDTH                    3  /* R2_2BOOSTVOL - [6:4] */
+#define WM8983_AUXR2BOOSTVOL_MASK               0x0007  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8983_AUXR2BOOSTVOL_SHIFT                   0  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8983_AUXR2BOOSTVOL_WIDTH                   3  /* AUXR2BOOSTVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output ctrl
+ */
+#define WM8983_DACL2RMIX                        0x0040  /* DACL2RMIX */
+#define WM8983_DACL2RMIX_MASK                   0x0040  /* DACL2RMIX */
+#define WM8983_DACL2RMIX_SHIFT                       6  /* DACL2RMIX */
+#define WM8983_DACL2RMIX_WIDTH                       1  /* DACL2RMIX */
+#define WM8983_DACR2LMIX                        0x0020  /* DACR2LMIX */
+#define WM8983_DACR2LMIX_MASK                   0x0020  /* DACR2LMIX */
+#define WM8983_DACR2LMIX_SHIFT                       5  /* DACR2LMIX */
+#define WM8983_DACR2LMIX_WIDTH                       1  /* DACR2LMIX */
+#define WM8983_OUT4BOOST                        0x0010  /* OUT4BOOST */
+#define WM8983_OUT4BOOST_MASK                   0x0010  /* OUT4BOOST */
+#define WM8983_OUT4BOOST_SHIFT                       4  /* OUT4BOOST */
+#define WM8983_OUT4BOOST_WIDTH                       1  /* OUT4BOOST */
+#define WM8983_OUT3BOOST                        0x0008  /* OUT3BOOST */
+#define WM8983_OUT3BOOST_MASK                   0x0008  /* OUT3BOOST */
+#define WM8983_OUT3BOOST_SHIFT                       3  /* OUT3BOOST */
+#define WM8983_OUT3BOOST_WIDTH                       1  /* OUT3BOOST */
+#define WM8983_SPKBOOST                         0x0004  /* SPKBOOST */
+#define WM8983_SPKBOOST_MASK                    0x0004  /* SPKBOOST */
+#define WM8983_SPKBOOST_SHIFT                        2  /* SPKBOOST */
+#define WM8983_SPKBOOST_WIDTH                        1  /* SPKBOOST */
+#define WM8983_TSDEN                            0x0002  /* TSDEN */
+#define WM8983_TSDEN_MASK                       0x0002  /* TSDEN */
+#define WM8983_TSDEN_SHIFT                           1  /* TSDEN */
+#define WM8983_TSDEN_WIDTH                           1  /* TSDEN */
+#define WM8983_VROI                             0x0001  /* VROI */
+#define WM8983_VROI_MASK                        0x0001  /* VROI */
+#define WM8983_VROI_SHIFT                            0  /* VROI */
+#define WM8983_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R50 (0x32) - Left mixer ctrl
+ */
+#define WM8983_AUXLMIXVOL_MASK                  0x01C0  /* AUXLMIXVOL - [8:6] */
+#define WM8983_AUXLMIXVOL_SHIFT                      6  /* AUXLMIXVOL - [8:6] */
+#define WM8983_AUXLMIXVOL_WIDTH                      3  /* AUXLMIXVOL - [8:6] */
+#define WM8983_AUXL2LMIX                        0x0020  /* AUXL2LMIX */
+#define WM8983_AUXL2LMIX_MASK                   0x0020  /* AUXL2LMIX */
+#define WM8983_AUXL2LMIX_SHIFT                       5  /* AUXL2LMIX */
+#define WM8983_AUXL2LMIX_WIDTH                       1  /* AUXL2LMIX */
+#define WM8983_BYPLMIXVOL_MASK                  0x001C  /* BYPLMIXVOL - [4:2] */
+#define WM8983_BYPLMIXVOL_SHIFT                      2  /* BYPLMIXVOL - [4:2] */
+#define WM8983_BYPLMIXVOL_WIDTH                      3  /* BYPLMIXVOL - [4:2] */
+#define WM8983_BYPL2LMIX                        0x0002  /* BYPL2LMIX */
+#define WM8983_BYPL2LMIX_MASK                   0x0002  /* BYPL2LMIX */
+#define WM8983_BYPL2LMIX_SHIFT                       1  /* BYPL2LMIX */
+#define WM8983_BYPL2LMIX_WIDTH                       1  /* BYPL2LMIX */
+#define WM8983_DACL2LMIX                        0x0001  /* DACL2LMIX */
+#define WM8983_DACL2LMIX_MASK                   0x0001  /* DACL2LMIX */
+#define WM8983_DACL2LMIX_SHIFT                       0  /* DACL2LMIX */
+#define WM8983_DACL2LMIX_WIDTH                       1  /* DACL2LMIX */
+
+/*
+ * R51 (0x33) - Right mixer ctrl
+ */
+#define WM8983_AUXRMIXVOL_MASK                  0x01C0  /* AUXRMIXVOL - [8:6] */
+#define WM8983_AUXRMIXVOL_SHIFT                      6  /* AUXRMIXVOL - [8:6] */
+#define WM8983_AUXRMIXVOL_WIDTH                      3  /* AUXRMIXVOL - [8:6] */
+#define WM8983_AUXR2RMIX                        0x0020  /* AUXR2RMIX */
+#define WM8983_AUXR2RMIX_MASK                   0x0020  /* AUXR2RMIX */
+#define WM8983_AUXR2RMIX_SHIFT                       5  /* AUXR2RMIX */
+#define WM8983_AUXR2RMIX_WIDTH                       1  /* AUXR2RMIX */
+#define WM8983_BYPRMIXVOL_MASK                  0x001C  /* BYPRMIXVOL - [4:2] */
+#define WM8983_BYPRMIXVOL_SHIFT                      2  /* BYPRMIXVOL - [4:2] */
+#define WM8983_BYPRMIXVOL_WIDTH                      3  /* BYPRMIXVOL - [4:2] */
+#define WM8983_BYPR2RMIX                        0x0002  /* BYPR2RMIX */
+#define WM8983_BYPR2RMIX_MASK                   0x0002  /* BYPR2RMIX */
+#define WM8983_BYPR2RMIX_SHIFT                       1  /* BYPR2RMIX */
+#define WM8983_BYPR2RMIX_WIDTH                       1  /* BYPR2RMIX */
+#define WM8983_DACR2RMIX                        0x0001  /* DACR2RMIX */
+#define WM8983_DACR2RMIX_MASK                   0x0001  /* DACR2RMIX */
+#define WM8983_DACR2RMIX_SHIFT                       0  /* DACR2RMIX */
+#define WM8983_DACR2RMIX_WIDTH                       1  /* DACR2RMIX */
+
+/*
+ * R52 (0x34) - LOUT1 (HP) volume ctrl
+ */
+#define WM8983_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8983_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8983_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8983_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8983_LOUT1ZC                          0x0080  /* LOUT1ZC */
+#define WM8983_LOUT1ZC_MASK                     0x0080  /* LOUT1ZC */
+#define WM8983_LOUT1ZC_SHIFT                         7  /* LOUT1ZC */
+#define WM8983_LOUT1ZC_WIDTH                         1  /* LOUT1ZC */
+#define WM8983_LOUT1MUTE                        0x0040  /* LOUT1MUTE */
+#define WM8983_LOUT1MUTE_MASK                   0x0040  /* LOUT1MUTE */
+#define WM8983_LOUT1MUTE_SHIFT                       6  /* LOUT1MUTE */
+#define WM8983_LOUT1MUTE_WIDTH                       1  /* LOUT1MUTE */
+#define WM8983_LOUT1VOL_MASK                    0x003F  /* LOUT1VOL - [5:0] */
+#define WM8983_LOUT1VOL_SHIFT                        0  /* LOUT1VOL - [5:0] */
+#define WM8983_LOUT1VOL_WIDTH                        6  /* LOUT1VOL - [5:0] */
+
+/*
+ * R53 (0x35) - ROUT1 (HP) volume ctrl
+ */
+#define WM8983_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8983_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8983_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8983_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8983_ROUT1ZC                          0x0080  /* ROUT1ZC */
+#define WM8983_ROUT1ZC_MASK                     0x0080  /* ROUT1ZC */
+#define WM8983_ROUT1ZC_SHIFT                         7  /* ROUT1ZC */
+#define WM8983_ROUT1ZC_WIDTH                         1  /* ROUT1ZC */
+#define WM8983_ROUT1MUTE                        0x0040  /* ROUT1MUTE */
+#define WM8983_ROUT1MUTE_MASK                   0x0040  /* ROUT1MUTE */
+#define WM8983_ROUT1MUTE_SHIFT                       6  /* ROUT1MUTE */
+#define WM8983_ROUT1MUTE_WIDTH                       1  /* ROUT1MUTE */
+#define WM8983_ROUT1VOL_MASK                    0x003F  /* ROUT1VOL - [5:0] */
+#define WM8983_ROUT1VOL_SHIFT                        0  /* ROUT1VOL - [5:0] */
+#define WM8983_ROUT1VOL_WIDTH                        6  /* ROUT1VOL - [5:0] */
+
+/*
+ * R54 (0x36) - LOUT2 (SPK) volume ctrl
+ */
+#define WM8983_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8983_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8983_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8983_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8983_LOUT2ZC                          0x0080  /* LOUT2ZC */
+#define WM8983_LOUT2ZC_MASK                     0x0080  /* LOUT2ZC */
+#define WM8983_LOUT2ZC_SHIFT                         7  /* LOUT2ZC */
+#define WM8983_LOUT2ZC_WIDTH                         1  /* LOUT2ZC */
+#define WM8983_LOUT2MUTE                        0x0040  /* LOUT2MUTE */
+#define WM8983_LOUT2MUTE_MASK                   0x0040  /* LOUT2MUTE */
+#define WM8983_LOUT2MUTE_SHIFT                       6  /* LOUT2MUTE */
+#define WM8983_LOUT2MUTE_WIDTH                       1  /* LOUT2MUTE */
+#define WM8983_LOUT2VOL_MASK                    0x003F  /* LOUT2VOL - [5:0] */
+#define WM8983_LOUT2VOL_SHIFT                        0  /* LOUT2VOL - [5:0] */
+#define WM8983_LOUT2VOL_WIDTH                        6  /* LOUT2VOL - [5:0] */
+
+/*
+ * R55 (0x37) - ROUT2 (SPK) volume ctrl
+ */
+#define WM8983_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8983_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8983_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8983_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8983_ROUT2ZC                          0x0080  /* ROUT2ZC */
+#define WM8983_ROUT2ZC_MASK                     0x0080  /* ROUT2ZC */
+#define WM8983_ROUT2ZC_SHIFT                         7  /* ROUT2ZC */
+#define WM8983_ROUT2ZC_WIDTH                         1  /* ROUT2ZC */
+#define WM8983_ROUT2MUTE                        0x0040  /* ROUT2MUTE */
+#define WM8983_ROUT2MUTE_MASK                   0x0040  /* ROUT2MUTE */
+#define WM8983_ROUT2MUTE_SHIFT                       6  /* ROUT2MUTE */
+#define WM8983_ROUT2MUTE_WIDTH                       1  /* ROUT2MUTE */
+#define WM8983_ROUT2VOL_MASK                    0x003F  /* ROUT2VOL - [5:0] */
+#define WM8983_ROUT2VOL_SHIFT                        0  /* ROUT2VOL - [5:0] */
+#define WM8983_ROUT2VOL_WIDTH                        6  /* ROUT2VOL - [5:0] */
+
+/*
+ * R56 (0x38) - OUT3 mixer ctrl
+ */
+#define WM8983_OUT3MUTE                         0x0040  /* OUT3MUTE */
+#define WM8983_OUT3MUTE_MASK                    0x0040  /* OUT3MUTE */
+#define WM8983_OUT3MUTE_SHIFT                        6  /* OUT3MUTE */
+#define WM8983_OUT3MUTE_WIDTH                        1  /* OUT3MUTE */
+#define WM8983_OUT4_2OUT3                       0x0008  /* OUT4_2OUT3 */
+#define WM8983_OUT4_2OUT3_MASK                  0x0008  /* OUT4_2OUT3 */
+#define WM8983_OUT4_2OUT3_SHIFT                      3  /* OUT4_2OUT3 */
+#define WM8983_OUT4_2OUT3_WIDTH                      1  /* OUT4_2OUT3 */
+#define WM8983_BYPL2OUT3                        0x0004  /* BYPL2OUT3 */
+#define WM8983_BYPL2OUT3_MASK                   0x0004  /* BYPL2OUT3 */
+#define WM8983_BYPL2OUT3_SHIFT                       2  /* BYPL2OUT3 */
+#define WM8983_BYPL2OUT3_WIDTH                       1  /* BYPL2OUT3 */
+#define WM8983_LMIX2OUT3                        0x0002  /* LMIX2OUT3 */
+#define WM8983_LMIX2OUT3_MASK                   0x0002  /* LMIX2OUT3 */
+#define WM8983_LMIX2OUT3_SHIFT                       1  /* LMIX2OUT3 */
+#define WM8983_LMIX2OUT3_WIDTH                       1  /* LMIX2OUT3 */
+#define WM8983_LDAC2OUT3                        0x0001  /* LDAC2OUT3 */
+#define WM8983_LDAC2OUT3_MASK                   0x0001  /* LDAC2OUT3 */
+#define WM8983_LDAC2OUT3_SHIFT                       0  /* LDAC2OUT3 */
+#define WM8983_LDAC2OUT3_WIDTH                       1  /* LDAC2OUT3 */
+
+/*
+ * R57 (0x39) - OUT4 (MONO) mix ctrl
+ */
+#define WM8983_OUT3_2OUT4                       0x0080  /* OUT3_2OUT4 */
+#define WM8983_OUT3_2OUT4_MASK                  0x0080  /* OUT3_2OUT4 */
+#define WM8983_OUT3_2OUT4_SHIFT                      7  /* OUT3_2OUT4 */
+#define WM8983_OUT3_2OUT4_WIDTH                      1  /* OUT3_2OUT4 */
+#define WM8983_OUT4MUTE                         0x0040  /* OUT4MUTE */
+#define WM8983_OUT4MUTE_MASK                    0x0040  /* OUT4MUTE */
+#define WM8983_OUT4MUTE_SHIFT                        6  /* OUT4MUTE */
+#define WM8983_OUT4MUTE_WIDTH                        1  /* OUT4MUTE */
+#define WM8983_OUT4ATTN                         0x0020  /* OUT4ATTN */
+#define WM8983_OUT4ATTN_MASK                    0x0020  /* OUT4ATTN */
+#define WM8983_OUT4ATTN_SHIFT                        5  /* OUT4ATTN */
+#define WM8983_OUT4ATTN_WIDTH                        1  /* OUT4ATTN */
+#define WM8983_LMIX2OUT4                        0x0010  /* LMIX2OUT4 */
+#define WM8983_LMIX2OUT4_MASK                   0x0010  /* LMIX2OUT4 */
+#define WM8983_LMIX2OUT4_SHIFT                       4  /* LMIX2OUT4 */
+#define WM8983_LMIX2OUT4_WIDTH                       1  /* LMIX2OUT4 */
+#define WM8983_LDAC2OUT4                        0x0008  /* LDAC2OUT4 */
+#define WM8983_LDAC2OUT4_MASK                   0x0008  /* LDAC2OUT4 */
+#define WM8983_LDAC2OUT4_SHIFT                       3  /* LDAC2OUT4 */
+#define WM8983_LDAC2OUT4_WIDTH                       1  /* LDAC2OUT4 */
+#define WM8983_BYPR2OUT4                        0x0004  /* BYPR2OUT4 */
+#define WM8983_BYPR2OUT4_MASK                   0x0004  /* BYPR2OUT4 */
+#define WM8983_BYPR2OUT4_SHIFT                       2  /* BYPR2OUT4 */
+#define WM8983_BYPR2OUT4_WIDTH                       1  /* BYPR2OUT4 */
+#define WM8983_RMIX2OUT4                        0x0002  /* RMIX2OUT4 */
+#define WM8983_RMIX2OUT4_MASK                   0x0002  /* RMIX2OUT4 */
+#define WM8983_RMIX2OUT4_SHIFT                       1  /* RMIX2OUT4 */
+#define WM8983_RMIX2OUT4_WIDTH                       1  /* RMIX2OUT4 */
+#define WM8983_RDAC2OUT4                        0x0001  /* RDAC2OUT4 */
+#define WM8983_RDAC2OUT4_MASK                   0x0001  /* RDAC2OUT4 */
+#define WM8983_RDAC2OUT4_SHIFT                       0  /* RDAC2OUT4 */
+#define WM8983_RDAC2OUT4_WIDTH                       1  /* RDAC2OUT4 */
+
+/*
+ * R61 (0x3D) - BIAS CTRL
+ */
+#define WM8983_BIASCUT                          0x0100  /* BIASCUT */
+#define WM8983_BIASCUT_MASK                     0x0100  /* BIASCUT */
+#define WM8983_BIASCUT_SHIFT                         8  /* BIASCUT */
+#define WM8983_BIASCUT_WIDTH                         1  /* BIASCUT */
+#define WM8983_HALFIPBIAS                       0x0080  /* HALFIPBIAS */
+#define WM8983_HALFIPBIAS_MASK                  0x0080  /* HALFIPBIAS */
+#define WM8983_HALFIPBIAS_SHIFT                      7  /* HALFIPBIAS */
+#define WM8983_HALFIPBIAS_WIDTH                      1  /* HALFIPBIAS */
+#define WM8983_VBBIASTST_MASK                   0x0060  /* VBBIASTST - [6:5] */
+#define WM8983_VBBIASTST_SHIFT                       5  /* VBBIASTST - [6:5] */
+#define WM8983_VBBIASTST_WIDTH                       2  /* VBBIASTST - [6:5] */
+#define WM8983_BUFBIAS_MASK                     0x0018  /* BUFBIAS - [4:3] */
+#define WM8983_BUFBIAS_SHIFT                         3  /* BUFBIAS - [4:3] */
+#define WM8983_BUFBIAS_WIDTH                         2  /* BUFBIAS - [4:3] */
+#define WM8983_ADCBIAS_MASK                     0x0006  /* ADCBIAS - [2:1] */
+#define WM8983_ADCBIAS_SHIFT                         1  /* ADCBIAS - [2:1] */
+#define WM8983_ADCBIAS_WIDTH                         2  /* ADCBIAS - [2:1] */
+#define WM8983_HALFOPBIAS                       0x0001  /* HALFOPBIAS */
+#define WM8983_HALFOPBIAS_MASK                  0x0001  /* HALFOPBIAS */
+#define WM8983_HALFOPBIAS_SHIFT                      0  /* HALFOPBIAS */
+#define WM8983_HALFOPBIAS_WIDTH                      1  /* HALFOPBIAS */
+
+enum clk_src {
+       WM8983_CLKSRC_MCLK,
+       WM8983_CLKSRC_PLL
+};
+
+#endif /* _WM8983_H */
index 9e5ff78..6e85b88 100644 (file)
@@ -876,7 +876,7 @@ SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0,
                   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
 SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0,
                   right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
-
+SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
 };
 
 static const struct snd_soc_dapm_route routes[] = {
@@ -1434,6 +1434,7 @@ static int wm8993_probe(struct snd_soc_codec *codec)
 
        wm8993->hubs_data.hp_startup_mode = 1;
        wm8993->hubs_data.dcs_codes = -2;
+       wm8993->hubs_data.series_startup = 1;
 
        ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret != 0) {
index 83014a7..09e680a 100644 (file)
@@ -195,10 +195,6 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
                        aif + 1, rate);
        }
 
-       if (rate && rate < 3000000)
-               dev_warn(codec->dev, "AIF%dCLK is %dHz, should be >=3MHz for optimal performance\n",
-                        aif + 1, rate);
-
        wm8994->aifclk[aif] = rate;
 
        snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset,
@@ -1146,13 +1142,33 @@ SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
        late_enable_ev, SND_SOC_DAPM_PRE_PMU),
 SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
        late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0,
+       late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+
+SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
+                    left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer),
+                    late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
+                    right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer),
+                    late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux,
+                  late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux,
+                  late_enable_ev, SND_SOC_DAPM_PRE_PMU),
 
 SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
 };
 
 static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
 SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0)
+SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
+                  left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
+SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
+                  right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
 };
 
 static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
@@ -1282,14 +1298,6 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),
 SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
 
-SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
-SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
-
-SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
-                  left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
-SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
-                  right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
-
 SND_SOC_DAPM_POST("Debug log", post_ev),
 };
 
@@ -1624,6 +1632,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        int reg_offset, ret;
        struct fll_div fll;
        u16 reg, aif1, aif2;
+       unsigned long timeout;
 
        aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
                & WM8994_AIF1CLK_ENA;
@@ -1705,6 +1714,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                            (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
                            (src - 1));
 
+       /* Clear any pending completion from a previous failure */
+       try_wait_for_completion(&wm8994->fll_locked[id]);
+
        /* Enable (with fractional mode if required) */
        if (freq_out) {
                if (fll.k)
@@ -1715,7 +1727,15 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                                    WM8994_FLL1_ENA | WM8994_FLL1_FRAC,
                                    reg);
 
-               msleep(5);
+               if (wm8994->fll_locked_irq) {
+                       timeout = wait_for_completion_timeout(&wm8994->fll_locked[id],
+                                                             msecs_to_jiffies(10));
+                       if (timeout == 0)
+                               dev_warn(codec->dev,
+                                        "Timed out waiting for FLL lock\n");
+               } else {
+                       msleep(5);
+               }
        }
 
        wm8994->fll[id].in = freq_in;
@@ -1733,6 +1753,14 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        return 0;
 }
 
+static irqreturn_t wm8994_fll_locked_irq(int irq, void *data)
+{
+       struct completion *completion = data;
+
+       complete(completion);
+
+       return IRQ_HANDLED;
+}
 
 static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
 
@@ -2272,6 +2300,33 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
        return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
 }
 
+static void wm8994_aif_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int rate_reg = 0;
+
+       switch (dai->id) {
+       case 1:
+               rate_reg = WM8994_AIF1_RATE;
+               break;
+       case 2:
+               rate_reg = WM8994_AIF1_RATE;
+               break;
+       default:
+               break;
+       }
+
+       /* If the DAI is idle then configure the divider tree for the
+        * lowest output rate to save a little power if the clock is
+        * still active (eg, because it is system clock).
+        */
+       if (rate_reg && !dai->playback_active && !dai->capture_active)
+               snd_soc_update_bits(codec, rate_reg,
+                                   WM8994_AIF1_SR_MASK |
+                                   WM8994_AIF1CLK_RATE_MASK, 0x9);
+}
+
 static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -2338,6 +2393,7 @@ static struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
        .set_sysclk     = wm8994_set_dai_sysclk,
        .set_fmt        = wm8994_set_dai_fmt,
        .hw_params      = wm8994_hw_params,
+       .shutdown       = wm8994_aif_shutdown,
        .digital_mute   = wm8994_aif_mute,
        .set_pll        = wm8994_set_fll,
        .set_tristate   = wm8994_set_tristate,
@@ -2347,6 +2403,7 @@ static struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
        .set_sysclk     = wm8994_set_dai_sysclk,
        .set_fmt        = wm8994_set_dai_fmt,
        .hw_params      = wm8994_hw_params,
+       .shutdown       = wm8994_aif_shutdown,
        .digital_mute   = wm8994_aif_mute,
        .set_pll        = wm8994_set_fll,
        .set_tristate   = wm8994_set_tristate,
@@ -2850,6 +2907,15 @@ out:
        return IRQ_HANDLED;
 }
 
+static irqreturn_t wm8994_fifo_error(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+
+       dev_err(codec->dev, "FIFO error\n");
+
+       return IRQ_HANDLED;
+}
+
 static int wm8994_codec_probe(struct snd_soc_codec *codec)
 {
        struct wm8994 *control;
@@ -2868,6 +2934,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        wm8994->pdata = dev_get_platdata(codec->dev->parent);
        wm8994->codec = codec;
 
+       for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
+               init_completion(&wm8994->fll_locked[i]);
+
        if (wm8994->pdata && wm8994->pdata->micdet_irq)
                wm8994->micdet_irq = wm8994->pdata->micdet_irq;
        else if (wm8994->pdata && wm8994->pdata->irq_base)
@@ -2906,6 +2975,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                        wm8994->hubs.dcs_codes = -5;
                        wm8994->hubs.hp_startup_mode = 1;
                        wm8994->hubs.dcs_readback_mode = 1;
+                       wm8994->hubs.series_startup = 1;
                        break;
                default:
                        wm8994->hubs.dcs_readback_mode = 1;
@@ -2920,6 +2990,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        }
 
+       wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR,
+                          wm8994_fifo_error, "FIFO error", codec);
+
+       ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
+                                wm_hubs_dcs_done, "DC servo done",
+                                &wm8994->hubs);
+       if (ret == 0)
+               wm8994->hubs.dcs_done_irq = true;
+
        switch (control->type) {
        case WM8994:
                if (wm8994->micdet_irq) {
@@ -2976,6 +3055,16 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                }
        }
 
+       wm8994->fll_locked_irq = true;
+       for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) {
+               ret = wm8994_request_irq(codec->control_data,
+                                        WM8994_IRQ_FLL1_LOCK + i,
+                                        wm8994_fll_locked_irq, "FLL lock",
+                                        &wm8994->fll_locked[i]);
+               if (ret != 0)
+                       wm8994->fll_locked_irq = false;
+       }
+
        /* Remember if AIFnLRCLK is configured as a GPIO.  This should be
         * configured on init - if a system wants to do this dynamically
         * at runtime we can deal with that then.
@@ -3051,10 +3140,18 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                            1 << WM8994_AIF2DAC_3D_GAIN_SHIFT,
                            1 << WM8994_AIF2DAC_3D_GAIN_SHIFT);
 
-       /* Unconditionally enable AIF1 ADC TDM mode; it only affects
-        * behaviour on idle TDM clock cycles. */
-       snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1,
-                           WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM);
+       /* Unconditionally enable AIF1 ADC TDM mode on chips which can
+        * use this; it only affects behaviour on idle TDM clock
+        * cycles. */
+       switch (control->type) {
+       case WM8994:
+       case WM8958:
+               snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1,
+                                   WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM);
+               break;
+       default:
+               break;
+       }
 
        wm8994_update_class_w(codec);
 
@@ -3153,6 +3250,12 @@ err_irq:
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
        if (wm8994->micdet_irq)
                free_irq(wm8994->micdet_irq, wm8994);
+       for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
+               wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i,
+                               &wm8994->fll_locked[i]);
+       wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
+                       &wm8994->hubs);
+       wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
 err:
        kfree(wm8994);
        return ret;
@@ -3162,11 +3265,20 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = codec->control_data;
+       int i;
 
        wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        pm_runtime_disable(codec->dev);
 
+       for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
+               wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i,
+                               &wm8994->fll_locked[i]);
+
+       wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
+                       &wm8994->hubs);
+       wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
+
        switch (control->type) {
        case WM8994:
                if (wm8994->micdet_irq)
index 0a1db04..1ab2266 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <sound/soc.h>
 #include <linux/firmware.h>
+#include <linux/completion.h>
 
 #include "wm_hubs.h"
 
@@ -79,6 +80,8 @@ struct wm8994_priv {
        int mclk[2];
        int aifclk[2];
        struct wm8994_fll_config fll[2], fll_suspend[2];
+       struct completion fll_locked[2];
+       bool fll_locked_irq;
 
        int dac_rates[2];
        int lrclk_shared[2];
index 91c6b39..a469132 100644 (file)
@@ -727,7 +727,7 @@ SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0,
 SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0),
 
 SND_SOC_DAPM_PGA("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0),
+SND_SOC_DAPM_OUT_DRV("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0),
 
 SND_SOC_DAPM_OUTPUT("LINEOUT"),
 SND_SOC_DAPM_OUTPUT("SPKN"),
index 9e370d1..4cc2d56 100644 (file)
@@ -63,8 +63,10 @@ static const struct soc_enum speaker_mode =
 
 static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
 {
+       struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        unsigned int reg;
        int count = 0;
+       int timeout;
        unsigned int val;
 
        val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1;
@@ -74,18 +76,39 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
 
        dev_dbg(codec->dev, "Waiting for DC servo...\n");
 
+       if (hubs->dcs_done_irq)
+               timeout = 4;
+       else
+               timeout = 400;
+
        do {
                count++;
-               msleep(1);
+
+               if (hubs->dcs_done_irq)
+                       wait_for_completion_timeout(&hubs->dcs_done,
+                                                   msecs_to_jiffies(250));
+               else
+                       msleep(1);
+
                reg = snd_soc_read(codec, WM8993_DC_SERVO_0);
                dev_dbg(codec->dev, "DC servo: %x\n", reg);
-       } while (reg & op && count < 400);
+       } while (reg & op && count < timeout);
 
        if (reg & op)
                dev_err(codec->dev, "Timed out waiting for DC Servo %x\n",
                        op);
 }
 
+irqreturn_t wm_hubs_dcs_done(int irq, void *data)
+{
+       struct wm_hubs_data *hubs = data;
+
+       complete(&hubs->dcs_done);
+
+       return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
+
 /*
  * Startup calibration of the DC servo
  */
@@ -107,8 +130,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                return;
        }
 
-       /* Devices not using a DCS code correction have startup mode */
-       if (hubs->dcs_codes) {
+       if (hubs->series_startup) {
                /* Set for 32 series updates */
                snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
                                    WM8993_DCS_SERIES_NO_01_MASK,
@@ -134,9 +156,9 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                break;
        case 1:
                reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
-               reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
+               reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
                        >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
-               reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
+               reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
                break;
        default:
                WARN(1, "Unknown DCS readback method\n");
@@ -150,13 +172,13 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                dev_dbg(codec->dev, "Applying %d code DC servo correction\n",
                        hubs->dcs_codes);
 
-               /* HPOUT1L */
-               offset = reg_l;
+               /* HPOUT1R */
+               offset = reg_r;
                offset += hubs->dcs_codes;
                dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 
-               /* HPOUT1R */
-               offset = reg_r;
+               /* HPOUT1L */
+               offset = reg_l;
                offset += hubs->dcs_codes;
                dcs_cfg |= (u8)offset;
 
@@ -168,8 +190,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                                  WM8993_DCS_TRIG_DAC_WR_0 |
                                  WM8993_DCS_TRIG_DAC_WR_1);
        } else {
-               dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
-               dcs_cfg |= reg_r;
+               dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+               dcs_cfg |= reg_l;
        }
 
        /* Save the callibrated offset if we're in class W mode and
@@ -195,7 +217,7 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
 
        /* If we're applying an offset correction then updating the
         * callibration would be likely to introduce further offsets. */
-       if (hubs->dcs_codes)
+       if (hubs->dcs_codes || hubs->no_series_update)
                return ret;
 
        /* Only need to do this if the outputs are active */
@@ -599,9 +621,6 @@ SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0,
 SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0,
                   in2r_pga, ARRAY_SIZE(in2r_pga)),
 
-/* Dummy widgets to represent differential paths */
-SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
-
 SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0,
                   mixinl, ARRAY_SIZE(mixinl)),
 SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0,
@@ -867,8 +886,11 @@ EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls);
 int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
                                int lineout1_diff, int lineout2_diff)
 {
+       struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+       init_completion(&hubs->dcs_done);
+
        snd_soc_dapm_add_routes(dapm, analogue_routes,
                                ARRAY_SIZE(analogue_routes));
 
index f8a5e97..676b125 100644 (file)
@@ -14,6 +14,9 @@
 #ifndef _WM_HUBS_H
 #define _WM_HUBS_H
 
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+
 struct snd_soc_codec;
 
 extern const unsigned int wm_hubs_spkmix_tlv[];
@@ -23,9 +26,14 @@ struct wm_hubs_data {
        int dcs_codes;
        int dcs_readback_mode;
        int hp_startup_mode;
+       int series_startup;
+       int no_series_update;
 
        bool class_w;
        u16 class_w_dcs;
+
+       bool dcs_done_irq;
+       struct completion dcs_done;
 };
 
 extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *);
@@ -36,4 +44,6 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *,
                                         int jd_scthr, int jd_thr,
                                         int micbias1_lvl, int micbias2_lvl);
 
+extern irqreturn_t wm_hubs_dcs_done(int irq, void *data);
+
 #endif
index 9d35b8c..a49e667 100644 (file)
@@ -46,11 +46,28 @@ static void print_buf_info(int slot, char *name)
 }
 #endif
 
+#define DAVINCI_PCM_FMTBITS    (\
+                               SNDRV_PCM_FMTBIT_S8     |\
+                               SNDRV_PCM_FMTBIT_U8     |\
+                               SNDRV_PCM_FMTBIT_S16_LE |\
+                               SNDRV_PCM_FMTBIT_S16_BE |\
+                               SNDRV_PCM_FMTBIT_U16_LE |\
+                               SNDRV_PCM_FMTBIT_U16_BE |\
+                               SNDRV_PCM_FMTBIT_S24_LE |\
+                               SNDRV_PCM_FMTBIT_S24_BE |\
+                               SNDRV_PCM_FMTBIT_U24_LE |\
+                               SNDRV_PCM_FMTBIT_U24_BE |\
+                               SNDRV_PCM_FMTBIT_S32_LE |\
+                               SNDRV_PCM_FMTBIT_S32_BE |\
+                               SNDRV_PCM_FMTBIT_U32_LE |\
+                               SNDRV_PCM_FMTBIT_U32_BE)
+
 static struct snd_pcm_hardware pcm_hardware_playback = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME|
+                SNDRV_PCM_INFO_BATCH),
+       .formats = DAVINCI_PCM_FMTBITS,
        .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
@@ -59,7 +76,7 @@ static struct snd_pcm_hardware pcm_hardware_playback = {
        .rate_min = 8000,
        .rate_max = 96000,
        .channels_min = 2,
-       .channels_max = 2,
+       .channels_max = 384,
        .buffer_bytes_max = 128 * 1024,
        .period_bytes_min = 32,
        .period_bytes_max = 8 * 1024,
@@ -71,8 +88,9 @@ static struct snd_pcm_hardware pcm_hardware_playback = {
 static struct snd_pcm_hardware pcm_hardware_capture = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_PAUSE),
-       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+                SNDRV_PCM_INFO_PAUSE |
+                SNDRV_PCM_INFO_BATCH),
+       .formats = DAVINCI_PCM_FMTBITS,
        .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
@@ -81,7 +99,7 @@ static struct snd_pcm_hardware pcm_hardware_capture = {
        .rate_min = 8000,
        .rate_max = 96000,
        .channels_min = 2,
-       .channels_max = 2,
+       .channels_max = 384,
        .buffer_bytes_max = 128 * 1024,
        .period_bytes_min = 32,
        .period_bytes_max = 8 * 1024,
@@ -139,6 +157,22 @@ struct davinci_runtime_data {
        struct edmacc_param ram_params;
 };
 
+static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream)
+{
+       struct davinci_runtime_data *prtd = substream->runtime->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       prtd->period++;
+       if (unlikely(prtd->period >= runtime->periods))
+               prtd->period = 0;
+}
+
+static void davinci_pcm_period_reset(struct snd_pcm_substream *substream)
+{
+       struct davinci_runtime_data *prtd = substream->runtime->private_data;
+
+       prtd->period = 0;
+}
 /*
  * Not used with ping/pong
  */
@@ -199,10 +233,6 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
        else
                edma_set_transfer_params(link, acnt, fifo_level, count,
                                                        fifo_level, ABSYNC);
-
-       prtd->period++;
-       if (unlikely(prtd->period >= runtime->periods))
-               prtd->period = 0;
 }
 
 static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
@@ -217,12 +247,13 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
                return;
 
        if (snd_pcm_running(substream)) {
+               spin_lock(&prtd->lock);
                if (prtd->ram_channel < 0) {
                        /* No ping/pong must fix up link dma data*/
-                       spin_lock(&prtd->lock);
                        davinci_pcm_enqueue_dma(substream);
-                       spin_unlock(&prtd->lock);
                }
+               davinci_pcm_period_elapsed(substream);
+               spin_unlock(&prtd->lock);
                snd_pcm_period_elapsed(substream);
        }
 }
@@ -425,7 +456,8 @@ static int request_ping_pong(struct snd_pcm_substream *substream,
 
        edma_read_slot(link, &prtd->asp_params);
        prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
-       prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f);
+       prtd->asp_params.opt |= TCCHEN |
+               EDMA_TCC(prtd->ram_channel & 0x3f);
        edma_write_slot(link, &prtd->asp_params);
 
        /* pong */
@@ -439,7 +471,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream,
        prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
        /* interrupt after every pong completion */
        prtd->asp_params.opt |= TCINTEN | TCCHEN |
-               EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel));
+               EDMA_TCC(prtd->ram_channel & 0x3f);
        edma_write_slot(link, &prtd->asp_params);
 
        /* ram */
@@ -527,6 +559,13 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+               edma_start(prtd->asp_channel);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+                   prtd->ram_channel >= 0) {
+                       /* copy 1st iram buffer */
+                       edma_start(prtd->ram_channel);
+               }
+               break;
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                edma_resume(prtd->asp_channel);
@@ -550,6 +589,7 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct davinci_runtime_data *prtd = substream->runtime->private_data;
 
+       davinci_pcm_period_reset(substream);
        if (prtd->ram_channel >= 0) {
                int ret = ping_pong_dma_setup(substream);
                if (ret < 0)
@@ -565,21 +605,31 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
                print_buf_info(prtd->asp_link[0], "asp_link[0]");
                print_buf_info(prtd->asp_link[1], "asp_link[1]");
 
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       /* copy 1st iram buffer */
-                       edma_start(prtd->ram_channel);
-               }
-               edma_start(prtd->asp_channel);
+               /*
+                * There is a phase offset of 2 periods between the position
+                * used by dma setup and the position reported in the pointer
+                * function.
+                *
+                * The phase offset, when not using ping-pong buffers, is due to
+                * the two consecutive calls to davinci_pcm_enqueue_dma() below.
+                *
+                * Whereas here, with ping-pong buffers, the phase is due to
+                * there being an entire buffer transfer complete before the
+                * first dma completion event triggers davinci_pcm_dma_irq().
+                */
+               davinci_pcm_period_elapsed(substream);
+               davinci_pcm_period_elapsed(substream);
+
                return 0;
        }
-       prtd->period = 0;
        davinci_pcm_enqueue_dma(substream);
+       davinci_pcm_period_elapsed(substream);
 
        /* Copy self-linked parameter RAM entry into master channel */
        edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
        edma_write_slot(prtd->asp_channel, &prtd->asp_params);
        davinci_pcm_enqueue_dma(substream);
-       edma_start(prtd->asp_channel);
+       davinci_pcm_period_elapsed(substream);
 
        return 0;
 }
@@ -591,51 +641,23 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream)
        struct davinci_runtime_data *prtd = runtime->private_data;
        unsigned int offset;
        int asp_count;
-       dma_addr_t asp_src, asp_dst;
-
+       unsigned int period_size = snd_pcm_lib_period_bytes(substream);
+
+       /*
+        * There is a phase offset of 2 periods between the position used by dma
+        * setup and the position reported in the pointer function. Either +2 in
+        * the dma setup or -2 here in the pointer function (with wrapping,
+        * both) accounts for this offset -- choose the latter since it makes
+        * the first-time setup clearer.
+        */
        spin_lock(&prtd->lock);
-       if (prtd->ram_channel >= 0) {
-               int ram_count;
-               int mod_ram;
-               dma_addr_t ram_src, ram_dst;
-               unsigned int period_size = snd_pcm_lib_period_bytes(substream);
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       /* reading ram before asp should be safe
-                        * as long as the asp transfers less than a ping size
-                        * of bytes between the 2 reads
-                        */
-                       edma_get_position(prtd->ram_channel,
-                                       &ram_src, &ram_dst);
-                       edma_get_position(prtd->asp_channel,
-                                       &asp_src, &asp_dst);
-                       asp_count = asp_src - prtd->asp_params.src;
-                       ram_count = ram_src - prtd->ram_params.src;
-                       mod_ram = ram_count % period_size;
-                       mod_ram -= asp_count;
-                       if (mod_ram < 0)
-                               mod_ram += period_size;
-                       else if (mod_ram == 0) {
-                               if (snd_pcm_running(substream))
-                                       mod_ram += period_size;
-                       }
-                       ram_count -= mod_ram;
-                       if (ram_count < 0)
-                               ram_count += period_size * runtime->periods;
-               } else {
-                       edma_get_position(prtd->ram_channel,
-                                       &ram_src, &ram_dst);
-                       ram_count = ram_dst - prtd->ram_params.dst;
-               }
-               asp_count = ram_count;
-       } else {
-               edma_get_position(prtd->asp_channel, &asp_src, &asp_dst);
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       asp_count = asp_src - runtime->dma_addr;
-               else
-                       asp_count = asp_dst - runtime->dma_addr;
-       }
+       asp_count = prtd->period - 2;
        spin_unlock(&prtd->lock);
 
+       if (asp_count < 0)
+               asp_count += runtime->periods;
+       asp_count *= period_size;
+
        offset = bytes_to_frames(runtime, asp_count);
        if (offset >= runtime->buffer_size)
                offset = 0;
@@ -811,9 +833,11 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
 
 static u64 davinci_pcm_dmamask = 0xffffffff;
 
-static int davinci_pcm_new(struct snd_card *card,
-                          struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
        if (!card->dev->dma_mask)
index a07f99c..dd7ac53 100644 (file)
@@ -283,9 +283,11 @@ static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
 static u64 ep93xx_pcm_dmamask = 0xffffffff;
 
-static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-                         struct snd_pcm *pcm)
+static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        if (!card->dev->dma_mask)
index 6680c0b..732208c 100644 (file)
@@ -294,9 +294,11 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
  * Regardless of where the memory is actually allocated, since the device can
  * technically DMA to any 36-bit address, we do need to set the DMA mask to 36.
  */
-static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm)
+static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        static u64 fsl_dma_dmamask = DMA_BIT_MASK(36);
        int ret;
 
@@ -939,7 +941,7 @@ static int __devinit fsl_soc_dma_probe(struct platform_device *pdev)
 
        iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
        if (iprop)
-               dma->ssi_fifo_depth = *iprop;
+               dma->ssi_fifo_depth = be32_to_cpup(iprop);
        else
                 /* Older 8610 DTs didn't have the fifo-depth property */
                dma->ssi_fifo_depth = 8;
index 313e0cc..d48afea 100644 (file)
@@ -678,7 +678,12 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
                kfree(ssi_private);
                return ret;
        }
-       ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start);
+       ssi_private->ssi = of_iomap(np, 0);
+       if (!ssi_private->ssi) {
+               dev_err(&pdev->dev, "could not map device resources\n");
+               kfree(ssi_private);
+               return -ENOMEM;
+       }
        ssi_private->ssi_phys = res.start;
        ssi_private->irq = irq_of_parse_and_map(np, 0);
 
@@ -691,7 +696,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
        /* Determine the FIFO depth. */
        iprop = of_get_property(np, "fsl,fifo-depth", NULL);
        if (iprop)
-               ssi_private->fifo_depth = *iprop;
+               ssi_private->fifo_depth = be32_to_cpup(iprop);
        else
                 /* Older 8610 DTs didn't have the fifo-depth property */
                ssi_private->fifo_depth = 8;
index fff695c..19ad0c1 100644 (file)
@@ -299,10 +299,11 @@ static struct snd_pcm_ops psc_dma_ops = {
 };
 
 static u64 psc_dma_dmamask = 0xffffffff;
-static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
-                          struct snd_pcm *pcm)
+static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        size_t size = psc_dma_hardware.buffer_bytes_max;
        int rc = 0;
index c16c6b2..a192979 100644 (file)
@@ -233,7 +233,7 @@ static int get_parent_cell_index(struct device_node *np)
        if (!iprop)
                return -1;
 
-       return *iprop;
+       return be32_to_cpup(iprop);
 }
 
 /**
@@ -258,7 +258,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
        if (!iprop)
                return -EINVAL;
 
-       addr = *iprop;
+       addr = be32_to_cpup(iprop);
 
        bus = get_parent_cell_index(np);
        if (bus < 0)
@@ -305,7 +305,7 @@ static int get_dma_channel(struct device_node *ssi_np,
                return -EINVAL;
        }
 
-       *dma_channel_id = *iprop;
+       *dma_channel_id = be32_to_cpup(iprop);
        *dma_id = get_parent_cell_index(dma_channel_np);
        of_node_put(dma_channel_np);
 
@@ -379,7 +379,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
                ret = -EINVAL;
                goto error;
        }
-       machine_data->ssi_id = *iprop;
+       machine_data->ssi_id = be32_to_cpup(iprop);
 
        /* Get the serial format and clock direction. */
        sprop = of_get_property(np, "fsl,mode", NULL);
@@ -405,7 +405,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
                        ret = -EINVAL;
                        goto error;
                }
-               machine_data->clk_frequency = *iprop;
+               machine_data->clk_frequency = be32_to_cpup(iprop);
        } else if (strcasecmp(sprop, "i2s-master") == 0) {
                machine_data->dai_format = SND_SOC_DAIFMT_I2S;
                machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
index 66e0b68..8fa4d5f 100644 (file)
@@ -232,7 +232,7 @@ static int get_parent_cell_index(struct device_node *np)
 
        iprop = of_get_property(parent, "cell-index", NULL);
        if (iprop)
-               ret = *iprop;
+               ret = be32_to_cpup(iprop);
 
        of_node_put(parent);
 
@@ -261,7 +261,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
        if (!iprop)
                return -EINVAL;
 
-       addr = *iprop;
+       addr = be32_to_cpup(iprop);
 
        bus = get_parent_cell_index(np);
        if (bus < 0)
@@ -308,7 +308,7 @@ static int get_dma_channel(struct device_node *ssi_np,
                return -EINVAL;
        }
 
-       *dma_channel_id = *iprop;
+       *dma_channel_id = be32_to_cpup(iprop);
        *dma_id = get_parent_cell_index(dma_channel_np);
        of_node_put(dma_channel_np);
 
@@ -379,7 +379,7 @@ static int p1022_ds_probe(struct platform_device *pdev)
                ret = -EINVAL;
                goto error;
        }
-       mdata->ssi_id = *iprop;
+       mdata->ssi_id = be32_to_cpup(iprop);
 
        /* Get the serial format and clock direction. */
        sprop = of_get_property(np, "fsl,mode", NULL);
@@ -405,7 +405,7 @@ static int p1022_ds_probe(struct platform_device *pdev)
                        ret = -EINVAL;
                        goto error;
                }
-               mdata->clk_frequency = *iprop;
+               mdata->clk_frequency = be32_to_cpup(iprop);
        } else if (strcasecmp(sprop, "i2s-master") == 0) {
                mdata->dai_format = SND_SOC_DAIFMT_I2S;
                mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
index 413b78d..309c59e 100644 (file)
@@ -238,12 +238,14 @@ static struct snd_pcm_ops imx_pcm_ops = {
 
 static int ssi_irq = 0;
 
-static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm)
+static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
-       ret = imx_pcm_new(card, dai, pcm);
+       ret = imx_pcm_new(rtd);
        if (ret)
                return ret;
 
index 61fceb0..10a8e27 100644 (file)
@@ -388,10 +388,11 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 
 static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
 
-int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm)
+int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
-
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        if (!card->dev->dma_mask)
index dc8a875..0a84cec 100644 (file)
@@ -225,8 +225,7 @@ struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
                struct imx_ssi *ssi);
 
 int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
-int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm);
+int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
 void imx_pcm_free(struct snd_pcm *pcm);
 
 /*
index fb1483f..a7c9578 100644 (file)
@@ -299,9 +299,11 @@ static void jz4740_pcm_free(struct snd_pcm *pcm)
 
 static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
 
-int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm)
+int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        if (!card->dev->dma_mask)
index e13c6ce..cd33de1 100644 (file)
@@ -312,9 +312,11 @@ static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
        return 0;
 }
 
-static int kirkwood_dma_new(struct snd_card *card,
-               struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
        if (!card->dev->dma_mask)
index 5a946b4..3e78260 100644 (file)
@@ -402,9 +402,10 @@ static void sst_pcm_free(struct snd_pcm *pcm)
        snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
-int sst_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-                       struct snd_pcm *pcm)
+int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int retval = 0;
 
        pr_debug("sst_pcm_new called\n");
index dac6732..9c0edad 100644 (file)
@@ -356,7 +356,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
        nuc900_audio->irq_num = platform_get_irq(pdev, 0);
        if (!nuc900_audio->irq_num) {
                ret = -EBUSY;
-               goto out2;
+               goto out3;
        }
 
        nuc900_ac97_data = nuc900_audio;
index 8263f56..d589ef1 100644 (file)
@@ -315,9 +315,12 @@ static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)
 }
 
 static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32);
-static int nuc900_dma_new(struct snd_card *card,
-       struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
+
        if (!card->dev->dma_mask)
                card->dev->dma_mask = &nuc900_pcm_dmamask;
        if (!card->dev->coherent_dma_mask)
index 99054cf..fe83d0d 100644 (file)
@@ -9,6 +9,9 @@ config SND_OMAP_SOC_MCBSP
 config SND_OMAP_SOC_MCPDM
        tristate
 
+config SND_OMAP_SOC_HDMI
+       tristate
+
 config SND_OMAP_SOC_N810
        tristate "SoC Audio support for Nokia N810"
        depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C
@@ -100,6 +103,14 @@ config SND_OMAP_SOC_SDP4430
          Say Y if you want to add support for SoC audio on Texas Instruments
          SDP4430.
 
+config SND_OMAP_SOC_OMAP4_HDMI
+       tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
+       depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4
+       select SND_OMAP_SOC_HDMI
+       help
+         Say Y if you want to add support for SoC HDMI audio on Texas Instruments
+         OMAP4 chips
+
 config SND_OMAP_SOC_OMAP3_PANDORA
        tristate "SoC Audio support for OMAP3 Pandora"
        depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA
index 6c2c87e..59e2c8d 100644 (file)
@@ -2,10 +2,12 @@
 snd-soc-omap-objs := omap-pcm.o
 snd-soc-omap-mcbsp-objs := omap-mcbsp.o
 snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o
+snd-soc-omap-hdmi-objs := omap-hdmi.o
 
 obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
 obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
 obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
+obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o
 
 # OMAP Machine Support
 snd-soc-n810-objs := n810.o
@@ -21,6 +23,7 @@ snd-soc-omap3pandora-objs := omap3pandora.o
 snd-soc-omap3beagle-objs := omap3beagle.o
 snd-soc-zoom2-objs := zoom2.o
 snd-soc-igep0020-objs := igep0020.o
+snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
@@ -36,3 +39,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
 obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
 obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
+obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o
index 462cbcb..b40095a 100644 (file)
@@ -427,7 +427,8 @@ static struct snd_soc_ops ams_delta_ops = {
 
 /* Board specific codec bias level control */
 static int ams_delta_set_bias_level(struct snd_soc_card *card,
-                                       enum snd_soc_bias_level level)
+                                   struct snd_soc_dapm_context *dapm,
+                                   enum snd_soc_bias_level level)
 {
        struct snd_soc_codec *codec = card->rtd->codec;
 
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c
new file mode 100644 (file)
index 0000000..36c6eae
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * omap-hdmi.c
+ *
+ * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors: Jorge Candelaria <jorge.candelaria@ti.com>
+ *          Ricardo Neri <ricardo.neri@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/dma.h>
+#include "omap-pcm.h"
+#include "omap-hdmi.h"
+
+#define DRV_NAME "hdmi-audio-dai"
+
+static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = {
+       .name = "HDMI playback",
+       .sync_mode = OMAP_DMA_SYNC_PACKET,
+};
+
+static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       int err;
+       /*
+        * Make sure that the period bytes are multiple of the DMA packet size.
+        * Largest packet size we use is 32 32-bit words = 128 bytes
+        */
+       err = snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params,
+                                   struct snd_soc_dai *dai)
+{
+       int err = 0;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               omap_hdmi_dai_dma_params.packet_size = 16;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               omap_hdmi_dai_dma_params.packet_size = 32;
+               break;
+       default:
+               err = -EINVAL;
+       }
+
+       omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+
+       snd_soc_dai_set_dma_data(dai, substream,
+                                &omap_hdmi_dai_dma_params);
+
+       return err;
+}
+
+static struct snd_soc_dai_ops omap_hdmi_dai_ops = {
+       .startup        = omap_hdmi_dai_startup,
+       .hw_params      = omap_hdmi_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver omap_hdmi_dai = {
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = OMAP_HDMI_RATES,
+               .formats = OMAP_HDMI_FORMATS,
+       },
+       .ops = &omap_hdmi_dai_ops,
+};
+
+static __devinit int omap_hdmi_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *hdmi_rsrc;
+
+       hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!hdmi_rsrc) {
+               dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n");
+               return -EINVAL;
+       }
+
+       omap_hdmi_dai_dma_params.port_addr =  hdmi_rsrc->start
+               + OMAP_HDMI_AUDIO_DMA_PORT;
+
+       hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!hdmi_rsrc) {
+               dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n");
+               return -EINVAL;
+       }
+
+       omap_hdmi_dai_dma_params.dma_req =  hdmi_rsrc->start;
+
+       ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
+       return ret;
+}
+
+static int __devexit omap_hdmi_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver hdmi_dai_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = omap_hdmi_probe,
+       .remove = __devexit_p(omap_hdmi_remove),
+};
+
+static int __init hdmi_dai_init(void)
+{
+       return platform_driver_register(&hdmi_dai_driver);
+}
+module_init(hdmi_dai_init);
+
+static void __exit hdmi_dai_exit(void)
+{
+       platform_driver_unregister(&hdmi_dai_driver);
+}
+module_exit(hdmi_dai_exit);
+
+MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@ti.com>");
+MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
+MODULE_DESCRIPTION("OMAP HDMI SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h
new file mode 100644 (file)
index 0000000..34c298d
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * omap-hdmi.h
+ *
+ * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors: Jorge Candelaria <jorge.candelaria@ti.com>
+ *          Ricardo Neri <ricardo.neri@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_HDMI_H__
+#define __OMAP_HDMI_H__
+
+#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c
+
+#define OMAP_HDMI_RATES        (SNDRV_PCM_RATE_32000 | \
+                               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+                               SNDRV_PCM_FMTBIT_S24_LE)
+
+#endif
index e6a6b99..b2f5751 100644 (file)
@@ -366,9 +366,11 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
        }
 }
 
-static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-                struct snd_pcm *pcm)
+static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        if (!card->dev->dma_mask)
diff --git a/sound/soc/omap/omap4-hdmi-card.c b/sound/soc/omap/omap4-hdmi-card.c
new file mode 100644 (file)
index 0000000..9f32615
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * omap4-hdmi-card.c
+ *
+ * OMAP ALSA SoC machine driver for TI OMAP4 HDMI
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Ricardo Neri <ricardo.neri@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/mach-types.h>
+#include <video/omapdss.h>
+
+#define DRV_NAME "omap4-hdmi-audio"
+
+static int omap4_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       int i;
+       struct omap_overlay_manager *mgr = NULL;
+       struct device *dev = substream->pcm->card->dev;
+
+       /* Find DSS HDMI device */
+       for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
+               mgr = omap_dss_get_overlay_manager(i);
+               if (mgr && mgr->device
+                       && mgr->device->type == OMAP_DISPLAY_TYPE_HDMI)
+                       break;
+       }
+
+       if (i == omap_dss_get_num_overlay_managers()) {
+               dev_err(dev, "HDMI display device not found!\n");
+               return -ENODEV;
+       }
+
+       /* Make sure HDMI is power-on to avoid L3 interconnect errors */
+       if (mgr->device->state != OMAP_DSS_DISPLAY_ACTIVE) {
+               dev_err(dev, "HDMI display is not active!\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops omap4_hdmi_dai_ops = {
+       .hw_params = omap4_hdmi_dai_hw_params,
+};
+
+static struct snd_soc_dai_link omap4_hdmi_dai = {
+       .name = "HDMI",
+       .stream_name = "HDMI",
+       .cpu_dai_name = "hdmi-audio-dai",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "omapdss_hdmi",
+       .codec_dai_name = "hdmi-audio-codec",
+       .ops = &omap4_hdmi_dai_ops,
+};
+
+static struct snd_soc_card snd_soc_omap4_hdmi = {
+       .name = "OMAP4HDMI",
+       .dai_link = &omap4_hdmi_dai,
+       .num_links = 1,
+};
+
+static __devinit int omap4_hdmi_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &snd_soc_omap4_hdmi;
+       int ret;
+
+       card->dev = &pdev->dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+               card->dev = NULL;
+               return ret;
+       }
+       return 0;
+}
+
+static int __devexit omap4_hdmi_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+       card->dev = NULL;
+       return 0;
+}
+
+static struct platform_driver omap4_hdmi_driver = {
+       .driver = {
+               .name = "omap4-hdmi-audio",
+               .owner = THIS_MODULE,
+       },
+       .probe = omap4_hdmi_probe,
+       .remove = __devexit_p(omap4_hdmi_remove),
+};
+
+static int __init omap4_hdmi_init(void)
+{
+       return platform_driver_register(&omap4_hdmi_driver);
+}
+module_init(omap4_hdmi_init);
+
+static void __exit omap4_hdmi_exit(void)
+{
+       platform_driver_unregister(&omap4_hdmi_driver);
+}
+module_exit(omap4_hdmi_exit);
+
+MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
+MODULE_DESCRIPTION("OMAP4 HDMI machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index fab20a5..c430600 100644 (file)
@@ -85,9 +85,10 @@ static struct snd_pcm_ops pxa2xx_pcm_ops = {
 
 static u64 pxa2xx_pcm_dmamask = DMA_BIT_MASK(32);
 
-static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-       struct snd_pcm *pcm)
+static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        if (!card->dev->dma_mask)
index ab3ccae..80c85fd 100644 (file)
@@ -443,10 +443,11 @@ static void s6000_pcm_free(struct snd_pcm *pcm)
 
 static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32);
 
-static int s6000_pcm_new(struct snd_card *card,
-                        struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime)
 {
-       struct snd_soc_pcm_runtime *runtime = pcm->private_data;
+       struct snd_card *card = runtime->card->snd_card;
+       struct snd_soc_dai *dai = runtime->cpu_dai;
+       struct snd_pcm *pcm = runtime->pcm;
        struct s6000_pcm_dma_params *params;
        int res;
 
index d155cbb..54b0e4b 100644 (file)
@@ -158,7 +158,7 @@ config SND_SOC_GONI_AQUILA_WM8994
 
 config SND_SOC_SAMSUNG_SMDK_SPDIF
        tristate "SoC S/PDIF Audio support for SMDK"
-       depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
+       depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310)
        select SND_SAMSUNG_SPDIF
        help
          Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
@@ -171,9 +171,23 @@ config SND_SOC_SMDK_WM8580_PCM
        help
          Say Y if you want to add support for SoC audio on the SMDK.
 
+config SND_SOC_SMDK_WM8994_PCM
+       tristate "SoC PCM Audio support for WM8994 on SMDK"
+       depends on SND_SOC_SAMSUNG && (MACH_SMDKC210 || MACH_SMDKV310)
+       select SND_SOC_WM8994
+       select SND_SAMSUNG_PCM
+       help
+         Say Y if you want to add support for SoC audio on the SMDK
+
 config SND_SOC_SPEYSIDE
        tristate "Audio support for Wolfson Speyside"
        depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8915
        select SND_SOC_WM9081
+
+config SND_SOC_SPEYSIDE_WM8962
+       tristate "Audio support for Wolfson Speyside with WM8962"
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       select SND_SAMSUNG_I2S
+       select SND_SOC_WM8962
index 683843a..9eb3b12 100644 (file)
@@ -35,7 +35,9 @@ snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
 snd-soc-goni-wm8994-objs := goni_wm8994.o
 snd-soc-smdk-spdif-objs := smdk_spdif.o
 snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o
+snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o
 snd-soc-speyside-objs := speyside.o
+snd-soc-speyside-wm8962-objs := speyside_wm8962.o
 
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -54,4 +56,6 @@ obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
 obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
 obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o
+obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o
 obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
+obj-$(CONFIG_SND_SOC_SPEYSIDE_WM8962) += snd-soc-speyside-wm8962.o
index 5cb3b88..9465588 100644 (file)
@@ -425,9 +425,11 @@ static void dma_free_dma_buffers(struct snd_pcm *pcm)
 
 static u64 dma_mask = DMA_BIT_MASK(32);
 
-static int dma_new(struct snd_card *card,
-       struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int dma_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        pr_debug("Entered %s\n", __func__);
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h
new file mode 100644 (file)
index 0000000..c0e6d9a
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * linux/sound/soc/samsung/i2s-regs.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung I2S driver's register header
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SND_SOC_SAMSUNG_I2S_REGS_H
+#define __SND_SOC_SAMSUNG_I2S_REGS_H
+
+#define I2SCON         0x0
+#define I2SMOD         0x4
+#define I2SFIC         0x8
+#define I2SPSR         0xc
+#define I2STXD         0x10
+#define I2SRXD         0x14
+#define I2SFICS                0x18
+#define I2STXDS                0x1c
+#define I2SAHB         0x20
+#define I2SSTR0                0x24
+#define I2SSIZE                0x28
+#define I2STRNCNT      0x2c
+#define I2SLVL0ADDR    0x30
+#define I2SLVL1ADDR    0x34
+#define I2SLVL2ADDR    0x38
+#define I2SLVL3ADDR    0x3c
+
+#define CON_RSTCLR             (1 << 31)
+#define CON_FRXOFSTATUS                (1 << 26)
+#define CON_FRXORINTEN         (1 << 25)
+#define CON_FTXSURSTAT         (1 << 24)
+#define CON_FTXSURINTEN                (1 << 23)
+#define CON_TXSDMA_PAUSE       (1 << 20)
+#define CON_TXSDMA_ACTIVE      (1 << 18)
+
+#define CON_FTXURSTATUS                (1 << 17)
+#define CON_FTXURINTEN         (1 << 16)
+#define CON_TXFIFO2_EMPTY      (1 << 15)
+#define CON_TXFIFO1_EMPTY      (1 << 14)
+#define CON_TXFIFO2_FULL       (1 << 13)
+#define CON_TXFIFO1_FULL       (1 << 12)
+
+#define CON_LRINDEX            (1 << 11)
+#define CON_TXFIFO_EMPTY       (1 << 10)
+#define CON_RXFIFO_EMPTY       (1 << 9)
+#define CON_TXFIFO_FULL                (1 << 8)
+#define CON_RXFIFO_FULL                (1 << 7)
+#define CON_TXDMA_PAUSE                (1 << 6)
+#define CON_RXDMA_PAUSE                (1 << 5)
+#define CON_TXCH_PAUSE         (1 << 4)
+#define CON_RXCH_PAUSE         (1 << 3)
+#define CON_TXDMA_ACTIVE       (1 << 2)
+#define CON_RXDMA_ACTIVE       (1 << 1)
+#define CON_ACTIVE             (1 << 0)
+
+#define MOD_OPCLK_CDCLK_OUT    (0 << 30)
+#define MOD_OPCLK_CDCLK_IN     (1 << 30)
+#define MOD_OPCLK_BCLK_OUT     (2 << 30)
+#define MOD_OPCLK_PCLK         (3 << 30)
+#define MOD_OPCLK_MASK         (3 << 30)
+#define MOD_TXS_IDMA           (1 << 28) /* Sec_TXFIFO use I-DMA */
+
+#define MOD_BLCS_SHIFT         26
+#define MOD_BLCS_16BIT         (0 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_8BIT          (1 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_24BIT         (2 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_MASK          (3 << MOD_BLCS_SHIFT)
+#define MOD_BLCP_SHIFT         24
+#define MOD_BLCP_16BIT         (0 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_8BIT          (1 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_24BIT         (2 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_MASK          (3 << MOD_BLCP_SHIFT)
+
+#define MOD_C2DD_HHALF         (1 << 21) /* Discard Higher-half */
+#define MOD_C2DD_LHALF         (1 << 20) /* Discard Lower-half */
+#define MOD_C1DD_HHALF         (1 << 19)
+#define MOD_C1DD_LHALF         (1 << 18)
+#define MOD_DC2_EN             (1 << 17)
+#define MOD_DC1_EN             (1 << 16)
+#define MOD_BLC_16BIT          (0 << 13)
+#define MOD_BLC_8BIT           (1 << 13)
+#define MOD_BLC_24BIT          (2 << 13)
+#define MOD_BLC_MASK           (3 << 13)
+
+#define MOD_IMS_SYSMUX         (1 << 10)
+#define MOD_SLAVE              (1 << 11)
+#define MOD_TXONLY             (0 << 8)
+#define MOD_RXONLY             (1 << 8)
+#define MOD_TXRX               (2 << 8)
+#define MOD_MASK               (3 << 8)
+#define MOD_LR_LLOW            (0 << 7)
+#define MOD_LR_RLOW            (1 << 7)
+#define MOD_SDF_IIS            (0 << 5)
+#define MOD_SDF_MSB            (1 << 5)
+#define MOD_SDF_LSB            (2 << 5)
+#define MOD_SDF_MASK           (3 << 5)
+#define MOD_RCLK_256FS         (0 << 3)
+#define MOD_RCLK_512FS         (1 << 3)
+#define MOD_RCLK_384FS         (2 << 3)
+#define MOD_RCLK_768FS         (3 << 3)
+#define MOD_RCLK_MASK          (3 << 3)
+#define MOD_BCLK_32FS          (0 << 1)
+#define MOD_BCLK_48FS          (1 << 1)
+#define MOD_BCLK_16FS          (2 << 1)
+#define MOD_BCLK_24FS          (3 << 1)
+#define MOD_BCLK_MASK          (3 << 1)
+#define MOD_8BIT               (1 << 0)
+
+#define MOD_CDCLKCON           (1 << 12)
+
+#define PSR_PSREN              (1 << 15)
+
+#define FIC_TX2COUNT(x)                (((x) >>  24) & 0xf)
+#define FIC_TX1COUNT(x)                (((x) >>  16) & 0xf)
+
+#define FIC_TXFLUSH            (1 << 15)
+#define FIC_RXFLUSH            (1 << 7)
+
+#define FIC_TXCOUNT(x)         (((x) >>  8) & 0xf)
+#define FIC_RXCOUNT(x)         (((x) >>  0) & 0xf)
+#define FICS_TXCOUNT(x)                (((x) >>  8) & 0x7f)
+
+#define AHB_INTENLVL0          (1 << 24)
+#define AHB_LVL0INT            (1 << 20)
+#define AHB_CLRLVL0INT         (1 << 16)
+#define AHB_DMARLD             (1 << 5)
+#define AHB_INTMASK            (1 << 3)
+#define AHB_DMAEN              (1 << 0)
+#define AHB_LVLINTMASK         (0xf << 20)
+
+#define I2SSIZE_TRNMSK         (0xffff)
+#define I2SSIZE_SHIFT          (16)
+
+#endif /* __SND_SOC_SAMSUNG_I2S_REGS_H */
+
+
index 992a732..1568eea 100644 (file)
 
 #include "dma.h"
 #include "i2s.h"
-
-#define I2SCON         0x0
-#define I2SMOD         0x4
-#define I2SFIC         0x8
-#define I2SPSR         0xc
-#define I2STXD         0x10
-#define I2SRXD         0x14
-#define I2SFICS                0x18
-#define I2STXDS                0x1c
-
-#define CON_RSTCLR             (1 << 31)
-#define CON_FRXOFSTATUS                (1 << 26)
-#define CON_FRXORINTEN         (1 << 25)
-#define CON_FTXSURSTAT         (1 << 24)
-#define CON_FTXSURINTEN                (1 << 23)
-#define CON_TXSDMA_PAUSE       (1 << 20)
-#define CON_TXSDMA_ACTIVE      (1 << 18)
-
-#define CON_FTXURSTATUS                (1 << 17)
-#define CON_FTXURINTEN         (1 << 16)
-#define CON_TXFIFO2_EMPTY      (1 << 15)
-#define CON_TXFIFO1_EMPTY      (1 << 14)
-#define CON_TXFIFO2_FULL       (1 << 13)
-#define CON_TXFIFO1_FULL       (1 << 12)
-
-#define CON_LRINDEX            (1 << 11)
-#define CON_TXFIFO_EMPTY       (1 << 10)
-#define CON_RXFIFO_EMPTY       (1 << 9)
-#define CON_TXFIFO_FULL                (1 << 8)
-#define CON_RXFIFO_FULL                (1 << 7)
-#define CON_TXDMA_PAUSE                (1 << 6)
-#define CON_RXDMA_PAUSE                (1 << 5)
-#define CON_TXCH_PAUSE         (1 << 4)
-#define CON_RXCH_PAUSE         (1 << 3)
-#define CON_TXDMA_ACTIVE       (1 << 2)
-#define CON_RXDMA_ACTIVE       (1 << 1)
-#define CON_ACTIVE             (1 << 0)
-
-#define MOD_OPCLK_CDCLK_OUT    (0 << 30)
-#define MOD_OPCLK_CDCLK_IN     (1 << 30)
-#define MOD_OPCLK_BCLK_OUT     (2 << 30)
-#define MOD_OPCLK_PCLK         (3 << 30)
-#define MOD_OPCLK_MASK         (3 << 30)
-#define MOD_TXS_IDMA           (1 << 28) /* Sec_TXFIFO use I-DMA */
-
-#define MOD_BLCS_SHIFT 26
-#define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT)
-#define MOD_BLCS_8BIT  (1 << MOD_BLCS_SHIFT)
-#define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT)
-#define MOD_BLCS_MASK  (3 << MOD_BLCS_SHIFT)
-#define MOD_BLCP_SHIFT 24
-#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT)
-#define MOD_BLCP_8BIT  (1 << MOD_BLCP_SHIFT)
-#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT)
-#define MOD_BLCP_MASK  (3 << MOD_BLCP_SHIFT)
-
-#define MOD_C2DD_HHALF         (1 << 21) /* Discard Higher-half */
-#define MOD_C2DD_LHALF         (1 << 20) /* Discard Lower-half */
-#define MOD_C1DD_HHALF         (1 << 19)
-#define MOD_C1DD_LHALF         (1 << 18)
-#define MOD_DC2_EN             (1 << 17)
-#define MOD_DC1_EN             (1 << 16)
-#define MOD_BLC_16BIT          (0 << 13)
-#define MOD_BLC_8BIT           (1 << 13)
-#define MOD_BLC_24BIT          (2 << 13)
-#define MOD_BLC_MASK           (3 << 13)
-
-#define MOD_IMS_SYSMUX         (1 << 10)
-#define MOD_SLAVE              (1 << 11)
-#define MOD_TXONLY             (0 << 8)
-#define MOD_RXONLY             (1 << 8)
-#define MOD_TXRX               (2 << 8)
-#define MOD_MASK               (3 << 8)
-#define MOD_LR_LLOW            (0 << 7)
-#define MOD_LR_RLOW            (1 << 7)
-#define MOD_SDF_IIS            (0 << 5)
-#define MOD_SDF_MSB            (1 << 5)
-#define MOD_SDF_LSB            (2 << 5)
-#define MOD_SDF_MASK           (3 << 5)
-#define MOD_RCLK_256FS         (0 << 3)
-#define MOD_RCLK_512FS         (1 << 3)
-#define MOD_RCLK_384FS         (2 << 3)
-#define MOD_RCLK_768FS         (3 << 3)
-#define MOD_RCLK_MASK          (3 << 3)
-#define MOD_BCLK_32FS          (0 << 1)
-#define MOD_BCLK_48FS          (1 << 1)
-#define MOD_BCLK_16FS          (2 << 1)
-#define MOD_BCLK_24FS          (3 << 1)
-#define MOD_BCLK_MASK          (3 << 1)
-#define MOD_8BIT               (1 << 0)
-
-#define MOD_CDCLKCON           (1 << 12)
-
-#define PSR_PSREN              (1 << 15)
-
-#define FIC_TX2COUNT(x)                (((x) >>  24) & 0xf)
-#define FIC_TX1COUNT(x)                (((x) >>  16) & 0xf)
-
-#define FIC_TXFLUSH            (1 << 15)
-#define FIC_RXFLUSH            (1 << 7)
-#define FIC_TXCOUNT(x)         (((x) >>  8) & 0xf)
-#define FIC_RXCOUNT(x)         (((x) >>  0) & 0xf)
-#define FICS_TXCOUNT(x)                (((x) >>  8) & 0x7f)
+#include "i2s-regs.h"
 
 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
 
index e7c1009..45fbe2b 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include "../codecs/wm8994.h"
+#include <sound/pcm_params.h>
 
  /*
   * Default CFG switch settings to use this driver:
@@ -44,7 +45,9 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
        int ret;
 
        /* AIF1CLK should be >=3MHz for optimal performance */
-       if (params_rate(params) == 8000 || params_rate(params) == 11025)
+       if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE)
+               pll_out = params_rate(params) * 384;
+       else if (params_rate(params) == 8000 || params_rate(params) == 11025)
                pll_out = params_rate(params) * 512;
        else
                pll_out = params_rate(params) * 256;
diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c
new file mode 100644 (file)
index 0000000..5f21116
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *  sound/soc/samsung/smdk_wm8994pcm.c
+ *
+ *  Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *             http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or  modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "../codecs/wm8994.h"
+#include "dma.h"
+#include "pcm.h"
+
+/*
+ * Board Settings:
+ *  o '1' means 'ON'
+ *  o '0' means 'OFF'
+ *  o 'X' means 'Don't care'
+ *
+ * SMDKC210, SMDKV310: CFG3- 1001, CFG5-1000, CFG7-111111
+ */
+
+/*
+ * Configure audio route as :-
+ * $ amixer sset 'DAC1' on,on
+ * $ amixer sset 'Right Headphone Mux' 'DAC'
+ * $ amixer sset 'Left Headphone Mux' 'DAC'
+ * $ amixer sset 'DAC1R Mixer AIF1.1' on
+ * $ amixer sset 'DAC1L Mixer AIF1.1' on
+ * $ amixer sset 'IN2L' on
+ * $ amixer sset 'IN2L PGA IN2LN' on
+ * $ amixer sset 'MIXINL IN2L' on
+ * $ amixer sset 'AIF1ADC1L Mixer ADC/DMIC' on
+ * $ amixer sset 'IN2R' on
+ * $ amixer sset 'IN2R PGA IN2RN' on
+ * $ amixer sset 'MIXINR IN2R' on
+ * $ amixer sset 'AIF1ADC1R Mixer ADC/DMIC' on
+ */
+
+/* SMDK has a 16.9344MHZ crystal attached to WM8994 */
+#define SMDK_WM8994_FREQ 16934400
+
+static int smdk_wm8994_pcm_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       unsigned long mclk_freq;
+       int rfs, ret;
+
+       switch(params_rate(params)) {
+       case 8000:
+               rfs = 512;
+               break;
+       default:
+               dev_err(cpu_dai->dev, "%s:%d Sampling Rate %u not supported!\n",
+               __func__, __LINE__, params_rate(params));
+               return -EINVAL;
+       }
+
+       mclk_freq = params_rate(params) * rfs;
+
+       /* Set the codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B
+                               | SND_SOC_DAIFMT_IB_NF
+                               | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* Set the cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B
+                               | SND_SOC_DAIFMT_IB_NF
+                               | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+                                       mclk_freq, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
+                                       SMDK_WM8994_FREQ, mclk_freq);
+       if (ret < 0)
+               return ret;
+
+       /* Set PCM source clock on CPU */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX,
+                                       mclk_freq, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* Set SCLK_DIV for making bclk */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops smdk_wm8994_pcm_ops = {
+       .hw_params = smdk_wm8994_pcm_hw_params,
+};
+
+static struct snd_soc_dai_link smdk_dai[] = {
+       {
+               .name = "WM8994 PAIF PCM",
+               .stream_name = "Primary PCM",
+               .cpu_dai_name = "samsung-pcm.0",
+               .codec_dai_name = "wm8994-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8994-codec",
+               .ops = &smdk_wm8994_pcm_ops,
+       },
+};
+
+static struct snd_soc_card smdk_pcm = {
+       .name = "SMDK-PCM",
+       .dai_link = smdk_dai,
+       .num_links = 1,
+};
+
+static int __devinit snd_smdk_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+
+       smdk_pcm.dev = &pdev->dev;
+       ret = snd_soc_register_card(&smdk_pcm);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit snd_smdk_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_card(&smdk_pcm);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver snd_smdk_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "samsung-smdk-pcm",
+       },
+       .probe = snd_smdk_probe,
+       .remove = __devexit_p(snd_smdk_remove),
+};
+
+static int __init smdk_audio_init(void)
+{
+       return platform_driver_register(&snd_smdk_driver);
+}
+
+module_init(smdk_audio_init);
+
+static void __exit smdk_audio_exit(void)
+{
+       platform_driver_unregister(&snd_smdk_driver);
+}
+
+module_exit(smdk_audio_exit);
+
+MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK WM8994 for PCM");
+MODULE_LICENSE("GPL");
index 360a333..d6dee4d 100644 (file)
 #define WM8915_HPSEL_GPIO 214
 
 static int speyside_set_bias_level(struct snd_soc_card *card,
+                                  struct snd_soc_dapm_context *dapm,
                                   enum snd_soc_bias_level level)
 {
        struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
        int ret;
 
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
        switch (level) {
        case SND_SOC_BIAS_STANDBY:
-               ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK1,
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK2,
                                             32768, SND_SOC_CLOCK_IN);
                if (ret < 0)
                        return ret;
 
-               ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK1,
+               ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK2,
                                          0, 0, 0);
                if (ret < 0) {
                        pr_err("Failed to stop FLL\n");
                        return ret;
                }
+               break;
 
        default:
                break;
@@ -46,6 +51,45 @@ static int speyside_set_bias_level(struct snd_soc_card *card,
        return 0;
 }
 
+static int speyside_set_bias_level_post(struct snd_soc_card *card,
+                                       struct snd_soc_dapm_context *dapm,
+                                       enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+                       ret = snd_soc_dai_set_pll(codec_dai, 0,
+                                                 WM8915_FLL_MCLK2,
+                                                 32768, 48000 * 256);
+                       if (ret < 0) {
+                               pr_err("Failed to start FLL\n");
+                               return ret;
+                       }
+
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                                    WM8915_SYSCLK_FLL,
+                                                    48000 * 256,
+                                                    SND_SOC_CLOCK_IN);
+                       if (ret < 0)
+                               return ret;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       card->dapm.bias_level = level;
+
+       return 0;
+}
+
 static int speyside_hw_params(struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *params)
 {
@@ -66,16 +110,6 @@ static int speyside_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK1,
-                                 32768, 256 * 48000);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_FLL,
-                                    256 * 48000, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
        return 0;
 }
 
@@ -127,7 +161,7 @@ static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
-       ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
+       ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK2, 32768, 0);
        if (ret < 0)
                return ret;
 
@@ -267,6 +301,7 @@ static struct snd_soc_card speyside = {
        .num_configs = ARRAY_SIZE(speyside_codec_conf),
 
        .set_bias_level = speyside_set_bias_level,
+       .set_bias_level_post = speyside_set_bias_level_post,
 
        .controls = controls,
        .num_controls = ARRAY_SIZE(controls),
diff --git a/sound/soc/samsung/speyside_wm8962.c b/sound/soc/samsung/speyside_wm8962.c
new file mode 100644 (file)
index 0000000..8ac42bf
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Speyside with WM8962 audio support
+ *
+ * Copyright 2011 Wolfson Microelectronics
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+
+#include "../codecs/wm8962.h"
+
+static int speyside_wm8962_set_bias_level(struct snd_soc_card *card,
+                                         struct snd_soc_dapm_context *dapm,
+                                         enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+                       ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+                                                 WM8962_FLL_MCLK, 32768,
+                                                 44100 * 256);
+                       if (ret < 0)
+                               pr_err("Failed to start FLL: %d\n", ret);
+
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                                    WM8962_SYSCLK_FLL,
+                                                    44100 * 256,
+                                                    SND_SOC_CLOCK_IN);
+                       if (ret < 0) {
+                               pr_err("Failed to set SYSCLK: %d\n");
+                               return ret;
+                       }
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int speyside_wm8962_set_bias_level_post(struct snd_soc_card *card,
+                                              struct snd_soc_dapm_context *dapm,
+                                              enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
+                                            32768, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       pr_err("Failed to switch away from FLL: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+                                         0, 0, 0);
+               if (ret < 0) {
+                       pr_err("Failed to stop FLL: %d\n", ret);
+                       return ret;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       dapm->bias_level = level;
+
+       return 0;
+}
+
+static int speyside_wm8962_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops speyside_wm8962_ops = {
+       .hw_params = speyside_wm8962_hw_params,
+};
+
+static struct snd_soc_dai_link speyside_wm8962_dai[] = {
+       {
+               .name = "CPU",
+               .stream_name = "CPU",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm8962",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8962.1-001a",
+               .ops = &speyside_wm8962_ops,
+       },
+};
+
+static const struct snd_kcontrol_new controls[] = {
+       SOC_DAPM_PIN_SWITCH("Main Speaker"),
+};
+
+static struct snd_soc_dapm_widget widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+
+       SND_SOC_DAPM_SPK("Main Speaker", NULL),
+};
+
+static struct snd_soc_dapm_route audio_paths[] = {
+       { "Headphone", NULL, "HPOUTL" },
+       { "Headphone", NULL, "HPOUTR" },
+
+       { "Main Speaker", NULL, "SPKOUTL" },
+       { "Main Speaker", NULL, "SPKOUTR" },
+
+       { "MICBIAS", NULL, "Headset Mic" },
+       { "IN4L", NULL, "MICBIAS" },
+       { "IN4R", NULL, "MICBIAS" },
+
+       { "MICBIAS", NULL, "DMIC" },
+       { "DMICDAT", NULL, "MICBIAS" },
+};
+
+static struct snd_soc_jack speyside_wm8962_headset;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin speyside_wm8962_headset_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static int speyside_wm8962_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_codec *codec = card->rtd[0].codec;
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
+                                    32768, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_jack_new(codec, "Headset",
+                              SND_JACK_HEADSET | SND_JACK_BTN_0,
+                              &speyside_wm8962_headset);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_pins(&speyside_wm8962_headset,
+                                   ARRAY_SIZE(speyside_wm8962_headset_pins),
+                                   speyside_wm8962_headset_pins);
+       if (ret)
+               return ret;
+
+       wm8962_mic_detect(codec, &speyside_wm8962_headset);
+
+       return 0;
+}
+
+static struct snd_soc_card speyside_wm8962 = {
+       .name = "Speyside WM8962",
+       .dai_link = speyside_wm8962_dai,
+       .num_links = ARRAY_SIZE(speyside_wm8962_dai),
+
+       .set_bias_level = speyside_wm8962_set_bias_level,
+       .set_bias_level_post = speyside_wm8962_set_bias_level_post,
+
+       .controls = controls,
+       .num_controls = ARRAY_SIZE(controls),
+       .dapm_widgets = widgets,
+       .num_dapm_widgets = ARRAY_SIZE(widgets),
+       .dapm_routes = audio_paths,
+       .num_dapm_routes = ARRAY_SIZE(audio_paths),
+
+       .late_probe = speyside_wm8962_late_probe,
+};
+
+static __devinit int speyside_wm8962_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &speyside_wm8962;
+       int ret;
+
+       card->dev = &pdev->dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit speyside_wm8962_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static struct platform_driver speyside_wm8962_driver = {
+       .driver = {
+               .name = "speyside-wm8962",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = speyside_wm8962_probe,
+       .remove = __devexit_p(speyside_wm8962_remove),
+};
+
+static int __init speyside_wm8962_audio_init(void)
+{
+       return platform_driver_register(&speyside_wm8962_driver);
+}
+module_init(speyside_wm8962_audio_init);
+
+static void __exit speyside_wm8962_audio_exit(void)
+{
+       platform_driver_unregister(&speyside_wm8962_driver);
+}
+module_exit(speyside_wm8962_audio_exit);
+
+MODULE_DESCRIPTION("Speyside WM8962 audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:speyside-wm8962");
index c326d29..db74005 100644 (file)
@@ -327,10 +327,10 @@ static void camelot_pcm_free(struct snd_pcm *pcm)
        snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
-static int camelot_pcm_new(struct snd_card *card,
-                          struct snd_soc_dai *dai,
-                          struct snd_pcm *pcm)
+static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_pcm *pcm = rtd->pcm;
+
        /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
         * in MMAP mode (i.e. aplay -M)
         */
index 4a9da6b..8e112cc 100644 (file)
@@ -118,10 +118,38 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena
 /*
  * FSI driver use below type name for variable
  *
- * xxx_len     : data length
- * xxx_width   : data width
- * xxx_offset  : data offset
  * xxx_num     : number of data
+ * xxx_pos     : position of data
+ * xxx_capa    : capacity of data
+ */
+
+/*
+ *     period/frame/sample image
+ *
+ * ex) PCM (2ch)
+ *
+ * period pos                                     period pos
+ *   [n]                                            [n + 1]
+ *   |<-------------------- period--------------------->|
+ * ==|============================================ ... =|==
+ *   |                                                 |
+ *   ||<-----  frame ----->|<------ frame ----->|  ... |
+ *   |+--------------------+--------------------+- ... |
+ *   ||[ sample ][ sample ]|[ sample ][ sample ]|  ... |
+ *   |+--------------------+--------------------+- ... |
+ * ==|============================================ ... =|==
+ */
+
+/*
+ *     FSI FIFO image
+ *
+ *     |            |
+ *     |            |
+ *     | [ sample ] |
+ *     | [ sample ] |
+ *     | [ sample ] |
+ *     | [ sample ] |
+ *             --> go to codecs
  */
 
 /*
@@ -131,12 +159,11 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena
 struct fsi_stream {
        struct snd_pcm_substream *substream;
 
-       int fifo_max_num;
-
-       int buff_offset;
-       int buff_len;
-       int period_len;
-       int period_num;
+       int fifo_sample_capa;   /* sample capacity of FSI FIFO */
+       int buff_sample_capa;   /* sample capacity of ALSA buffer */
+       int buff_sample_pos;    /* sample position of ALSA buffer */
+       int period_samples;     /* sample number / 1 period */
+       int period_pos;         /* current period position */
 
        int uerr_num;
        int oerr_num;
@@ -149,17 +176,14 @@ struct fsi_priv {
        struct fsi_stream playback;
        struct fsi_stream capture;
 
+       u32 do_fmt;
+       u32 di_fmt;
+
        int chan_num:16;
        int clk_master:1;
+       int spdif:1;
 
        long rate;
-
-       /* for suspend/resume */
-       u32 saved_do_fmt;
-       u32 saved_di_fmt;
-       u32 saved_ckg1;
-       u32 saved_ckg2;
-       u32 saved_out_sel;
 };
 
 struct fsi_core {
@@ -180,14 +204,6 @@ struct fsi_master {
        struct fsi_core *core;
        struct sh_fsi_platform_info *info;
        spinlock_t lock;
-
-       /* for suspend/resume */
-       u32 saved_a_mclk;
-       u32 saved_b_mclk;
-       u32 saved_iemsk;
-       u32 saved_imsk;
-       u32 saved_clk_rst;
-       u32 saved_soft_rst;
 };
 
 /*
@@ -271,6 +287,11 @@ static int fsi_is_port_a(struct fsi_priv *fsi)
        return fsi->master->base == fsi->base;
 }
 
+static int fsi_is_spdif(struct fsi_priv *fsi)
+{
+       return fsi->spdif;
+}
+
 static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -342,28 +363,59 @@ static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play)
        return shift;
 }
 
+static int fsi_frame2sample(struct fsi_priv *fsi, int frames)
+{
+       return frames * fsi->chan_num;
+}
+
+static int fsi_sample2frame(struct fsi_priv *fsi, int samples)
+{
+       return samples / fsi->chan_num;
+}
+
+static int fsi_stream_is_working(struct fsi_priv *fsi,
+                                 int is_play)
+{
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct fsi_master *master = fsi_get_master(fsi);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&master->lock, flags);
+       ret = !!io->substream;
+       spin_unlock_irqrestore(&master->lock, flags);
+
+       return ret;
+}
+
 static void fsi_stream_push(struct fsi_priv *fsi,
                            int is_play,
-                           struct snd_pcm_substream *substream,
-                           u32 buffer_len,
-                           u32 period_len)
+                           struct snd_pcm_substream *substream)
 {
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct fsi_master *master = fsi_get_master(fsi);
+       unsigned long flags;
 
+       spin_lock_irqsave(&master->lock, flags);
        io->substream   = substream;
-       io->buff_len    = buffer_len;
-       io->buff_offset = 0;
-       io->period_len  = period_len;
-       io->period_num  = 0;
+       io->buff_sample_capa    = fsi_frame2sample(fsi, runtime->buffer_size);
+       io->buff_sample_pos     = 0;
+       io->period_samples      = fsi_frame2sample(fsi, runtime->period_size);
+       io->period_pos          = 0;
        io->oerr_num    = -1; /* ignore 1st err */
        io->uerr_num    = -1; /* ignore 1st err */
+       spin_unlock_irqrestore(&master->lock, flags);
 }
 
 static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
 {
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
        struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+       struct fsi_master *master = fsi_get_master(fsi);
+       unsigned long flags;
 
+       spin_lock_irqsave(&master->lock, flags);
 
        if (io->oerr_num > 0)
                dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
@@ -372,47 +424,27 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
                dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
 
        io->substream   = NULL;
-       io->buff_len    = 0;
-       io->buff_offset = 0;
-       io->period_len  = 0;
-       io->period_num  = 0;
+       io->buff_sample_capa    = 0;
+       io->buff_sample_pos     = 0;
+       io->period_samples      = 0;
+       io->period_pos          = 0;
        io->oerr_num    = 0;
        io->uerr_num    = 0;
+       spin_unlock_irqrestore(&master->lock, flags);
 }
 
-static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
+static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, int is_play)
 {
        u32 status;
-       int data_num;
+       int frames;
 
        status = is_play ?
                fsi_reg_read(fsi, DOFF_ST) :
                fsi_reg_read(fsi, DIFF_ST);
 
-       data_num = 0x1ff & (status >> 8);
-       data_num *= fsi->chan_num;
-
-       return data_num;
-}
-
-static int fsi_len2num(int len, int width)
-{
-       return len / width;
-}
-
-#define fsi_num2offset(a, b) fsi_num2len(a, b)
-static int fsi_num2len(int num, int width)
-{
-       return num * width;
-}
-
-static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
-{
-       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-       struct snd_pcm_substream *substream = io->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
+       frames = 0x1ff & (status >> 8);
 
-       return frames_to_bytes(runtime, 1) / fsi->chan_num;
+       return fsi_frame2sample(fsi, frames);
 }
 
 static void fsi_count_fifo_err(struct fsi_priv *fsi)
@@ -444,8 +476,10 @@ static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream)
 {
        int is_play = fsi_stream_is_play(stream);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct snd_pcm_runtime *runtime = io->substream->runtime;
 
-       return io->substream->runtime->dma_area + io->buff_offset;
+       return runtime->dma_area +
+               samples_to_bytes(runtime, io->buff_sample_pos);
 }
 
 static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num)
@@ -559,37 +593,94 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 /*
  *             clock function
  */
-#define fsi_module_init(m, d)  __fsi_module_clk_ctrl(m, d, 1)
-#define fsi_module_kill(m, d)  __fsi_module_clk_ctrl(m, d, 0)
-static void __fsi_module_clk_ctrl(struct fsi_master *master,
-                                 struct device *dev,
-                                 int enable)
+static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
+                             long rate, int enable)
 {
-       pm_runtime_get_sync(dev);
+       struct fsi_master *master = fsi_get_master(fsi);
+       set_rate_func set_rate = fsi_get_info_set_rate(master);
+       int fsi_ver = master->core->ver;
+       int ret;
 
-       if (enable) {
-               /* enable only SR */
-               fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR);
-               fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0);
-       } else {
-               /* clear all registers */
-               fsi_master_mask_set(master, SOFT_RST, FSISR, 0);
+       ret = set_rate(dev, fsi_is_port_a(fsi), rate, enable);
+       if (ret < 0) /* error */
+               return ret;
+
+       if (!enable)
+               return 0;
+
+       if (ret > 0) {
+               u32 data = 0;
+
+               switch (ret & SH_FSI_ACKMD_MASK) {
+               default:
+                       /* FALL THROUGH */
+               case SH_FSI_ACKMD_512:
+                       data |= (0x0 << 12);
+                       break;
+               case SH_FSI_ACKMD_256:
+                       data |= (0x1 << 12);
+                       break;
+               case SH_FSI_ACKMD_128:
+                       data |= (0x2 << 12);
+                       break;
+               case SH_FSI_ACKMD_64:
+                       data |= (0x3 << 12);
+                       break;
+               case SH_FSI_ACKMD_32:
+                       if (fsi_ver < 2)
+                               dev_err(dev, "unsupported ACKMD\n");
+                       else
+                               data |= (0x4 << 12);
+                       break;
+               }
+
+               switch (ret & SH_FSI_BPFMD_MASK) {
+               default:
+                       /* FALL THROUGH */
+               case SH_FSI_BPFMD_32:
+                       data |= (0x0 << 8);
+                       break;
+               case SH_FSI_BPFMD_64:
+                       data |= (0x1 << 8);
+                       break;
+               case SH_FSI_BPFMD_128:
+                       data |= (0x2 << 8);
+                       break;
+               case SH_FSI_BPFMD_256:
+                       data |= (0x3 << 8);
+                       break;
+               case SH_FSI_BPFMD_512:
+                       data |= (0x4 << 8);
+                       break;
+               case SH_FSI_BPFMD_16:
+                       if (fsi_ver < 2)
+                               dev_err(dev, "unsupported ACKMD\n");
+                       else
+                               data |= (0x7 << 8);
+                       break;
+               }
+
+               fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
+               udelay(10);
+               ret = 0;
        }
 
-       pm_runtime_put_sync(dev);
+       return ret;
 }
 
-#define fsi_port_start(f)      __fsi_port_clk_ctrl(f, 1)
-#define fsi_port_stop(f)       __fsi_port_clk_ctrl(f, 0)
-static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable)
+#define fsi_port_start(f, i)   __fsi_port_clk_ctrl(f, i, 1)
+#define fsi_port_stop(f, i)    __fsi_port_clk_ctrl(f, i, 0)
+static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int is_play, int enable)
 {
        struct fsi_master *master = fsi_get_master(fsi);
-       u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR;
        u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
-       int is_master = fsi_is_clk_master(fsi);
 
-       fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0);
-       if (is_master)
+       if (enable)
+               fsi_irq_enable(fsi, is_play);
+       else
+               fsi_irq_disable(fsi, is_play);
+
+       if (fsi_is_clk_master(fsi))
                fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
@@ -598,18 +689,19 @@ static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable)
  */
 static void fsi_fifo_init(struct fsi_priv *fsi,
                          int is_play,
-                         struct snd_soc_dai *dai)
+                         struct device *dev)
 {
        struct fsi_master *master = fsi_get_master(fsi);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
        u32 shift, i;
+       int frame_capa;
 
        /* get on-chip RAM capacity */
        shift = fsi_master_read(master, FIFO_SZ);
        shift >>= fsi_get_port_shift(fsi, is_play);
        shift &= FIFO_SZ_MASK;
-       io->fifo_max_num = 256 << shift;
-       dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num);
+       frame_capa = 256 << shift;
+       dev_dbg(dev, "fifo = %d words\n", frame_capa);
 
        /*
         * The maximum number of sample data varies depending
@@ -631,9 +723,11 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
         * 8 channels:  32 ( 32 x 8 = 256)
         */
        for (i = 1; i < fsi->chan_num; i <<= 1)
-               io->fifo_max_num >>= 1;
-       dev_dbg(dai->dev, "%d channel %d store\n",
-               fsi->chan_num, io->fifo_max_num);
+               frame_capa >>= 1;
+       dev_dbg(dev, "%d channel %d store\n",
+               fsi->chan_num, frame_capa);
+
+       io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa);
 
        /*
         * set interrupt generation factor
@@ -654,10 +748,10 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
        struct snd_pcm_substream *substream = NULL;
        int is_play = fsi_stream_is_play(stream);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-       int data_residue_num;
-       int data_num;
-       int data_num_max;
-       int ch_width;
+       int sample_residues;
+       int sample_width;
+       int samples;
+       int samples_max;
        int over_period;
        void (*fn)(struct fsi_priv *fsi, int size);
 
@@ -673,36 +767,35 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
        /* FSI FIFO has limit.
         * So, this driver can not send periods data at a time
         */
-       if (io->buff_offset >=
-           fsi_num2offset(io->period_num + 1, io->period_len)) {
+       if (io->buff_sample_pos >=
+           io->period_samples * (io->period_pos + 1)) {
 
                over_period = 1;
-               io->period_num = (io->period_num + 1) % runtime->periods;
+               io->period_pos = (io->period_pos + 1) % runtime->periods;
 
-               if (0 == io->period_num)
-                       io->buff_offset = 0;
+               if (0 == io->period_pos)
+                       io->buff_sample_pos = 0;
        }
 
-       /* get 1 channel data width */
-       ch_width = fsi_get_frame_width(fsi, is_play);
+       /* get 1 sample data width */
+       sample_width = samples_to_bytes(runtime, 1);
 
-       /* get residue data number of alsa */
-       data_residue_num = fsi_len2num(io->buff_len - io->buff_offset,
-                                      ch_width);
+       /* get number of residue samples */
+       sample_residues = io->buff_sample_capa - io->buff_sample_pos;
 
        if (is_play) {
                /*
                 * for play-back
                 *
-                * data_num_max : number of FSI fifo free space
-                * data_num     : number of ALSA residue data
+                * samples_max  : number of FSI fifo free samples space
+                * samples      : number of ALSA residue samples
                 */
-               data_num_max  = io->fifo_max_num * fsi->chan_num;
-               data_num_max -= fsi_get_fifo_data_num(fsi, is_play);
+               samples_max  = io->fifo_sample_capa;
+               samples_max -= fsi_get_current_fifo_samples(fsi, is_play);
 
-               data_num = data_residue_num;
+               samples = sample_residues;
 
-               switch (ch_width) {
+               switch (sample_width) {
                case 2:
                        fn = fsi_dma_soft_push16;
                        break;
@@ -716,13 +809,13 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
                /*
                 * for capture
                 *
-                * data_num_max : number of ALSA free space
-                * data_num     : number of data in FSI fifo
+                * samples_max  : number of ALSA free samples space
+                * samples      : number of samples in FSI fifo
                 */
-               data_num_max = data_residue_num;
-               data_num     = fsi_get_fifo_data_num(fsi, is_play);
+               samples_max = sample_residues;
+               samples     = fsi_get_current_fifo_samples(fsi, is_play);
 
-               switch (ch_width) {
+               switch (sample_width) {
                case 2:
                        fn = fsi_dma_soft_pop16;
                        break;
@@ -734,12 +827,12 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
                }
        }
 
-       data_num = min(data_num, data_num_max);
+       samples = min(samples, samples_max);
 
-       fn(fsi, data_num);
+       fn(fsi, samples);
 
-       /* update buff_offset */
-       io->buff_offset += fsi_num2offset(data_num, ch_width);
+       /* update buff_sample_pos */
+       io->buff_sample_pos += samples;
 
        if (over_period)
                snd_pcm_period_elapsed(substream);
@@ -788,16 +881,20 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
  *             dai ops
  */
 
-static int fsi_dai_startup(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
+static int fsi_hw_startup(struct fsi_priv *fsi,
+                         int is_play,
+                         struct device *dev)
 {
-       struct fsi_priv *fsi = fsi_get_priv(substream);
        u32 flags = fsi_get_info_flags(fsi);
-       u32 data;
-       int is_play = fsi_is_play(substream);
+       u32 data = 0;
 
-       pm_runtime_get_sync(dai->dev);
+       pm_runtime_get_sync(dev);
 
+       /* clock setting */
+       if (fsi_is_clk_master(fsi))
+               data = DIMD | DOMD;
+
+       fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
 
        /* clock inversion (CKG2) */
        data = 0;
@@ -812,54 +909,70 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
 
        fsi_reg_write(fsi, CKG2, data);
 
+       /* set format */
+       fsi_reg_write(fsi, DO_FMT, fsi->do_fmt);
+       fsi_reg_write(fsi, DI_FMT, fsi->di_fmt);
+
+       /* spdif ? */
+       if (fsi_is_spdif(fsi)) {
+               fsi_spdif_clk_ctrl(fsi, 1);
+               fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
+       }
+
        /* irq clear */
        fsi_irq_disable(fsi, is_play);
        fsi_irq_clear_status(fsi);
 
        /* fifo init */
-       fsi_fifo_init(fsi, is_play, dai);
+       fsi_fifo_init(fsi, is_play, dev);
 
        return 0;
 }
 
-static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
+static void fsi_hw_shutdown(struct fsi_priv *fsi,
+                           int is_play,
+                           struct device *dev)
+{
+       if (fsi_is_clk_master(fsi))
+               fsi_set_master_clk(dev, fsi, fsi->rate, 0);
+
+       pm_runtime_put_sync(dev);
+}
+
+static int fsi_dai_startup(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
        int is_play = fsi_is_play(substream);
-       struct fsi_master *master = fsi_get_master(fsi);
-       set_rate_func set_rate = fsi_get_info_set_rate(master);
 
-       fsi_irq_disable(fsi, is_play);
+       return fsi_hw_startup(fsi, is_play, dai->dev);
+}
 
-       if (fsi_is_clk_master(fsi))
-               set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
+static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct fsi_priv *fsi = fsi_get_priv(substream);
+       int is_play = fsi_is_play(substream);
 
+       fsi_hw_shutdown(fsi, is_play, dai->dev);
        fsi->rate = 0;
-
-       pm_runtime_put_sync(dai->dev);
 }
 
 static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                           struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int is_play = fsi_is_play(substream);
        int ret = 0;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               fsi_stream_push(fsi, is_play, substream,
-                               frames_to_bytes(runtime, runtime->buffer_size),
-                               frames_to_bytes(runtime, runtime->period_size));
+               fsi_stream_push(fsi, is_play, substream);
                ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
-               fsi_irq_enable(fsi, is_play);
-               fsi_port_start(fsi);
+               fsi_port_start(fsi, is_play);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               fsi_port_stop(fsi);
-               fsi_irq_disable(fsi, is_play);
+               fsi_port_stop(fsi, is_play);
                fsi_stream_pop(fsi, is_play);
                break;
        }
@@ -884,8 +997,8 @@ static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
                return -EINVAL;
        }
 
-       fsi_reg_write(fsi, DO_FMT, data);
-       fsi_reg_write(fsi, DI_FMT, data);
+       fsi->do_fmt = data;
+       fsi->di_fmt = data;
 
        return 0;
 }
@@ -900,11 +1013,10 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
 
        data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
        fsi->chan_num = 2;
-       fsi_spdif_clk_ctrl(fsi, 1);
-       fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
+       fsi->spdif = 1;
 
-       fsi_reg_write(fsi, DO_FMT, data);
-       fsi_reg_write(fsi, DI_FMT, data);
+       fsi->do_fmt = data;
+       fsi->di_fmt = data;
 
        return 0;
 }
@@ -915,32 +1027,24 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct fsi_master *master = fsi_get_master(fsi);
        set_rate_func set_rate = fsi_get_info_set_rate(master);
        u32 flags = fsi_get_info_flags(fsi);
-       u32 data = 0;
        int ret;
 
-       pm_runtime_get_sync(dai->dev);
-
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
-               data = DIMD | DOMD;
                fsi->clk_master = 1;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
                break;
        default:
-               ret = -EINVAL;
-               goto set_fmt_exit;
+               return -EINVAL;
        }
 
        if (fsi_is_clk_master(fsi) && !set_rate) {
                dev_err(dai->dev, "platform doesn't have set_rate\n");
-               ret = -EINVAL;
-               goto set_fmt_exit;
+               return -EINVAL;
        }
 
-       fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
-
        /* set format */
        switch (flags & SH_FSI_FMT_MASK) {
        case SH_FSI_FMT_DAI:
@@ -953,9 +1057,6 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                ret = -EINVAL;
        }
 
-set_fmt_exit:
-       pm_runtime_put_sync(dai->dev);
-
        return ret;
 }
 
@@ -964,79 +1065,19 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
-       struct fsi_master *master = fsi_get_master(fsi);
-       set_rate_func set_rate = fsi_get_info_set_rate(master);
-       int fsi_ver = master->core->ver;
        long rate = params_rate(params);
        int ret;
 
        if (!fsi_is_clk_master(fsi))
                return 0;
 
-       ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1);
-       if (ret < 0) /* error */
+       ret = fsi_set_master_clk(dai->dev, fsi, rate, 1);
+       if (ret < 0)
                return ret;
 
        fsi->rate = rate;
-       if (ret > 0) {
-               u32 data = 0;
-
-               switch (ret & SH_FSI_ACKMD_MASK) {
-               default:
-                       /* FALL THROUGH */
-               case SH_FSI_ACKMD_512:
-                       data |= (0x0 << 12);
-                       break;
-               case SH_FSI_ACKMD_256:
-                       data |= (0x1 << 12);
-                       break;
-               case SH_FSI_ACKMD_128:
-                       data |= (0x2 << 12);
-                       break;
-               case SH_FSI_ACKMD_64:
-                       data |= (0x3 << 12);
-                       break;
-               case SH_FSI_ACKMD_32:
-                       if (fsi_ver < 2)
-                               dev_err(dai->dev, "unsupported ACKMD\n");
-                       else
-                               data |= (0x4 << 12);
-                       break;
-               }
-
-               switch (ret & SH_FSI_BPFMD_MASK) {
-               default:
-                       /* FALL THROUGH */
-               case SH_FSI_BPFMD_32:
-                       data |= (0x0 << 8);
-                       break;
-               case SH_FSI_BPFMD_64:
-                       data |= (0x1 << 8);
-                       break;
-               case SH_FSI_BPFMD_128:
-                       data |= (0x2 << 8);
-                       break;
-               case SH_FSI_BPFMD_256:
-                       data |= (0x3 << 8);
-                       break;
-               case SH_FSI_BPFMD_512:
-                       data |= (0x4 << 8);
-                       break;
-               case SH_FSI_BPFMD_16:
-                       if (fsi_ver < 2)
-                               dev_err(dai->dev, "unsupported ACKMD\n");
-                       else
-                               data |= (0x7 << 8);
-                       break;
-               }
-
-               fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
-               udelay(10);
-               ret = 0;
-       }
 
        return ret;
-
 }
 
 static struct snd_soc_dai_ops fsi_dai_ops = {
@@ -1097,16 +1138,14 @@ static int fsi_hw_free(struct snd_pcm_substream *substream)
 
 static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsi_priv *fsi = fsi_get_priv(substream);
        struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream));
-       long location;
+       int samples_pos = io->buff_sample_pos - 1;
 
-       location = (io->buff_offset - 1);
-       if (location < 0)
-               location = 0;
+       if (samples_pos < 0)
+               samples_pos = 0;
 
-       return bytes_to_frames(runtime, location);
+       return fsi_sample2frame(fsi, samples_pos);
 }
 
 static struct snd_pcm_ops fsi_pcm_ops = {
@@ -1129,10 +1168,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm)
        snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
-static int fsi_pcm_new(struct snd_card *card,
-                      struct snd_soc_dai *dai,
-                      struct snd_pcm *pcm)
+static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_pcm *pcm = rtd->pcm;
+
        /*
         * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
         * in MMAP mode (i.e. aplay -M)
@@ -1246,8 +1285,6 @@ static int fsi_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        dev_set_drvdata(&pdev->dev, master);
 
-       fsi_module_init(master, &pdev->dev);
-
        ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED,
                          id_entry->name, master);
        if (ret) {
@@ -1290,8 +1327,6 @@ static int fsi_remove(struct platform_device *pdev)
 
        master = dev_get_drvdata(&pdev->dev);
 
-       fsi_module_kill(master, &pdev->dev);
-
        free_irq(master->irq, master);
        pm_runtime_disable(&pdev->dev);
 
@@ -1305,53 +1340,43 @@ static int fsi_remove(struct platform_device *pdev)
 }
 
 static void __fsi_suspend(struct fsi_priv *fsi,
-                         struct device *dev,
-                         set_rate_func set_rate)
+                         int is_play,
+                         struct device *dev)
 {
-       fsi->saved_do_fmt       = fsi_reg_read(fsi, DO_FMT);
-       fsi->saved_di_fmt       = fsi_reg_read(fsi, DI_FMT);
-       fsi->saved_ckg1         = fsi_reg_read(fsi, CKG1);
-       fsi->saved_ckg2         = fsi_reg_read(fsi, CKG2);
-       fsi->saved_out_sel      = fsi_reg_read(fsi, OUT_SEL);
+       if (!fsi_stream_is_working(fsi, is_play))
+               return;
 
-       if (fsi_is_clk_master(fsi))
-               set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0);
+       fsi_port_stop(fsi, is_play);
+       fsi_hw_shutdown(fsi, is_play, dev);
 }
 
 static void __fsi_resume(struct fsi_priv *fsi,
-                        struct device *dev,
-                        set_rate_func set_rate)
+                        int is_play,
+                        struct device *dev)
 {
-       fsi_reg_write(fsi, DO_FMT,      fsi->saved_do_fmt);
-       fsi_reg_write(fsi, DI_FMT,      fsi->saved_di_fmt);
-       fsi_reg_write(fsi, CKG1,        fsi->saved_ckg1);
-       fsi_reg_write(fsi, CKG2,        fsi->saved_ckg2);
-       fsi_reg_write(fsi, OUT_SEL,     fsi->saved_out_sel);
+       if (!fsi_stream_is_working(fsi, is_play))
+               return;
+
+       fsi_hw_startup(fsi, is_play, dev);
+
+       if (fsi_is_clk_master(fsi) && fsi->rate)
+               fsi_set_master_clk(dev, fsi, fsi->rate, 1);
+
+       fsi_port_start(fsi, is_play);
 
-       if (fsi_is_clk_master(fsi))
-               set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1);
 }
 
 static int fsi_suspend(struct device *dev)
 {
        struct fsi_master *master = dev_get_drvdata(dev);
-       set_rate_func set_rate = fsi_get_info_set_rate(master);
-
-       pm_runtime_get_sync(dev);
-
-       __fsi_suspend(&master->fsia, dev, set_rate);
-       __fsi_suspend(&master->fsib, dev, set_rate);
+       struct fsi_priv *fsia = &master->fsia;
+       struct fsi_priv *fsib = &master->fsib;
 
-       master->saved_a_mclk    = fsi_core_read(master, a_mclk);
-       master->saved_b_mclk    = fsi_core_read(master, b_mclk);
-       master->saved_iemsk     = fsi_core_read(master, iemsk);
-       master->saved_imsk      = fsi_core_read(master, imsk);
-       master->saved_clk_rst   = fsi_master_read(master, CLK_RST);
-       master->saved_soft_rst  = fsi_master_read(master, SOFT_RST);
+       __fsi_suspend(fsia, 1, dev);
+       __fsi_suspend(fsia, 0, dev);
 
-       fsi_module_kill(master, dev);
-
-       pm_runtime_put_sync(dev);
+       __fsi_suspend(fsib, 1, dev);
+       __fsi_suspend(fsib, 0, dev);
 
        return 0;
 }
@@ -1359,23 +1384,14 @@ static int fsi_suspend(struct device *dev)
 static int fsi_resume(struct device *dev)
 {
        struct fsi_master *master = dev_get_drvdata(dev);
-       set_rate_func set_rate = fsi_get_info_set_rate(master);
-
-       pm_runtime_get_sync(dev);
-
-       fsi_module_init(master, dev);
+       struct fsi_priv *fsia = &master->fsia;
+       struct fsi_priv *fsib = &master->fsib;
 
-       fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst);
-       fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst);
-       fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk);
-       fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk);
-       fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk);
-       fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk);
+       __fsi_resume(fsia, 1, dev);
+       __fsi_resume(fsia, 0, dev);
 
-       __fsi_resume(&master->fsia, dev, set_rate);
-       __fsi_resume(&master->fsib, dev, set_rate);
-
-       pm_runtime_put_sync(dev);
+       __fsi_resume(fsib, 1, dev);
+       __fsi_resume(fsib, 0, dev);
 
        return 0;
 }
index a423bab..f8f6816 100644 (file)
@@ -527,10 +527,11 @@ static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss)
        return bytes_to_frames(ss->runtime, ptr);
 }
 
-static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-                      struct snd_pcm *pcm)
+static int siu_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        /* card->dev == socdev->dev, see snd_soc_new_pcms() */
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_pcm *pcm = rtd->pcm;
        struct siu_info *info = siu_i2s_data;
        struct platform_device *pdev = to_platform_device(card->dev);
        int ret;
index 039b953..d9f8ade 100644 (file)
 
 #include <trace/events/asoc.h>
 
-#ifdef CONFIG_SPI_MASTER
-static int do_spi_write(void *control, const char *data, int len)
-{
-       struct spi_device *spi = control;
-       int ret;
-
-       ret = spi_write(spi, data, len);
-       if (ret < 0)
-               return ret;
-
-       return len;
-}
-#endif
-
-static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
-                      unsigned int value, const void *data, int len)
-{
-       int ret;
-
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-           reg < codec->driver->reg_cache_size &&
-           !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       ret = codec->hw_write(codec->control_data, data, len);
-       if (ret == len)
-               return 0;
-       if (ret < 0)
-               return ret;
-       else
-               return -EIO;
-}
-
-static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg)
-{
-       int ret;
-       unsigned int val;
-
-       if (reg >= codec->driver->reg_cache_size ||
-           snd_soc_codec_volatile_register(codec, reg) ||
-           codec->cache_bypass) {
-               if (codec->cache_only)
-                       return -1;
-
-               BUG_ON(!codec->hw_read);
-               return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-       return val;
-}
-
-static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
-                                     unsigned int reg)
-{
-       return do_hw_read(codec, reg);
-}
-
-static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
-                             unsigned int value)
-{
-       u16 data;
-
-       data = cpu_to_be16((reg << 12) | (value & 0xffffff));
-
-       return do_hw_write(codec, reg, value, &data, 2);
-}
-
-static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
-                                    unsigned int reg)
-{
-       return do_hw_read(codec, reg);
-}
-
-static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
-                            unsigned int value)
-{
-       u8 data[2];
-
-       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-       data[1] = value & 0x00ff;
-
-       return do_hw_write(codec, reg, value, data, 2);
-}
-
-static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
-                            unsigned int value)
-{
-       u8 data[2];
-
-       reg &= 0xff;
-       data[0] = reg;
-       data[1] = value & 0xff;
-
-       return do_hw_write(codec, reg, value, data, 2);
-}
-
-static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
-                                    unsigned int reg)
-{
-       return do_hw_read(codec, reg);
-}
-
-static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
-                             unsigned int value)
-{
-       u8 data[3];
-
-       data[0] = reg;
-       data[1] = (value >> 8) & 0xff;
-       data[2] = value & 0xff;
-
-       return do_hw_write(codec, reg, value, data, 3);
-}
-
-static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
-                                     unsigned int reg)
-{
-       return do_hw_read(codec, reg);
-}
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int do_i2c_read(struct snd_soc_codec *codec,
-                               void *reg, int reglen,
-                               void *data, int datalen)
-{
-       struct i2c_msg xfer[2];
-       int ret;
-       struct i2c_client *client = codec->control_data;
-
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = reglen;
-       xfer[0].buf = reg;
-
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = datalen;
-       xfer[1].buf = data;
-
-       ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret == 2)
-               return 0;
-       else if (ret < 0)
-               return ret;
-       else
-               return -EIO;
-}
-#endif
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
-                                        unsigned int r)
-{
-       u8 reg = r;
-       u8 data;
-       int ret;
-
-       ret = do_i2c_read(codec, &reg, 1, &data, 1);
-       if (ret < 0)
-               return 0;
-       return data;
-}
-#else
-#define snd_soc_8_8_read_i2c NULL
-#endif
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
-                                         unsigned int r)
-{
-       u8 reg = r;
-       u16 data;
-       int ret;
-
-       ret = do_i2c_read(codec, &reg, 1, &data, 2);
-       if (ret < 0)
-               return 0;
-       return (data >> 8) | ((data & 0xff) << 8);
-}
-#else
-#define snd_soc_8_16_read_i2c NULL
-#endif
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
-                                         unsigned int r)
-{
-       u16 reg = r;
-       u8 data;
-       int ret;
-
-       ret = do_i2c_read(codec, &reg, 2, &data, 1);
-       if (ret < 0)
-               return 0;
-       return data;
-}
-#else
-#define snd_soc_16_8_read_i2c NULL
-#endif
-
-static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
-                                     unsigned int reg)
-{
-       return do_hw_read(codec, reg);
-}
-
-static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
-                             unsigned int value)
-{
-       u8 data[3];
-
-       data[0] = (reg >> 8) & 0xff;
-       data[1] = reg & 0xff;
-       data[2] = value;
-
-       return do_hw_write(codec, reg, value, data, 3);
-}
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
-                                          unsigned int r)
-{
-       u16 reg = cpu_to_be16(r);
-       u16 data;
-       int ret;
-
-       ret = do_i2c_read(codec, &reg, 2, &data, 2);
-       if (ret < 0)
-               return 0;
-       return be16_to_cpu(data);
-}
-#else
-#define snd_soc_16_16_read_i2c NULL
-#endif
-
-static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
-                                      unsigned int reg)
-{
-       return do_hw_read(codec, reg);
-}
-
-static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
-                              unsigned int value)
-{
-       u8 data[4];
-
-       data[0] = (reg >> 8) & 0xff;
-       data[1] = reg & 0xff;
-       data[2] = (value >> 8) & 0xff;
-       data[3] = value & 0xff;
-
-       return do_hw_write(codec, reg, value, data, 4);
-}
-
-/* Primitive bulk write support for soc-cache.  The data pointed to by
- * `data' needs to already be in the form the hardware expects
- * including any leading register specific data.  Any data written
- * through this function will not go through the cache as it only
- * handles writing to volatile or out of bounds registers.
- */
-static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
-                                    const void *data, size_t len)
-{
-       int ret;
-
-       /* To ensure that we don't get out of sync with the cache, check
-        * whether the base register is volatile or if we've directly asked
-        * to bypass the cache.  Out of bounds registers are considered
-        * volatile.
-        */
-       if (!codec->cache_bypass
-           && !snd_soc_codec_volatile_register(codec, reg)
-           && reg < codec->driver->reg_cache_size)
-               return -EINVAL;
-
-       switch (codec->control_type) {
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-       case SND_SOC_I2C:
-               ret = i2c_master_send(codec->control_data, data, len);
-               break;
-#endif
-#if defined(CONFIG_SPI_MASTER)
-       case SND_SOC_SPI:
-               ret = spi_write(codec->control_data, data, len);
-               break;
-#endif
-       default:
-               BUG();
-       }
-
-       if (ret == len)
-               return 0;
-       if (ret < 0)
-               return ret;
-       else
-               return -EIO;
-}
-
-static struct {
-       int addr_bits;
-       int data_bits;
-       int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
-       unsigned int (*read)(struct snd_soc_codec *, unsigned int);
-       unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
-} io_types[] = {
-       {
-               .addr_bits = 4, .data_bits = 12,
-               .write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
-       },
-       {
-               .addr_bits = 7, .data_bits = 9,
-               .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
-       },
-       {
-               .addr_bits = 8, .data_bits = 8,
-               .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
-               .i2c_read = snd_soc_8_8_read_i2c,
-       },
-       {
-               .addr_bits = 8, .data_bits = 16,
-               .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
-               .i2c_read = snd_soc_8_16_read_i2c,
-       },
-       {
-               .addr_bits = 16, .data_bits = 8,
-               .write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
-               .i2c_read = snd_soc_16_8_read_i2c,
-       },
-       {
-               .addr_bits = 16, .data_bits = 16,
-               .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
-               .i2c_read = snd_soc_16_16_read_i2c,
-       },
-};
-
-/**
- * snd_soc_codec_set_cache_io: Set up standard I/O functions.
- *
- * @codec: CODEC to configure.
- * @addr_bits: Number of bits of register address data.
- * @data_bits: Number of bits of data per register.
- * @control: Control bus used.
- *
- * Register formats are frequently shared between many I2C and SPI
- * devices.  In order to promote code reuse the ASoC core provides
- * some standard implementations of CODEC read and write operations
- * which can be set up using this function.
- *
- * The caller is responsible for allocating and initialising the
- * actual cache.
- *
- * Note that at present this code cannot be used by CODECs with
- * volatile registers.
- */
-int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
-                              int addr_bits, int data_bits,
-                              enum snd_soc_control_type control)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(io_types); i++)
-               if (io_types[i].addr_bits == addr_bits &&
-                   io_types[i].data_bits == data_bits)
-                       break;
-       if (i == ARRAY_SIZE(io_types)) {
-               printk(KERN_ERR
-                      "No I/O functions for %d bit address %d bit data\n",
-                      addr_bits, data_bits);
-               return -EINVAL;
-       }
-
-       codec->write = io_types[i].write;
-       codec->read = io_types[i].read;
-       codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
-
-       switch (control) {
-       case SND_SOC_I2C:
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-               codec->hw_write = (hw_write_t)i2c_master_send;
-#endif
-               if (io_types[i].i2c_read)
-                       codec->hw_read = io_types[i].i2c_read;
-
-               codec->control_data = container_of(codec->dev,
-                                                  struct i2c_client,
-                                                  dev);
-               break;
-
-       case SND_SOC_SPI:
-#ifdef CONFIG_SPI_MASTER
-               codec->hw_write = do_spi_write;
-#endif
-
-               codec->control_data = container_of(codec->dev,
-                                                  struct spi_device,
-                                                  dev);
-               break;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
-
 static bool snd_soc_set_cache_val(void *base, unsigned int idx,
                                  unsigned int val, unsigned int word_size)
 {
@@ -483,31 +67,86 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
 }
 
 struct snd_soc_rbtree_node {
-       struct rb_node node;
-       unsigned int reg;
-       unsigned int value;
-       unsigned int defval;
+       struct rb_node node; /* the actual rbtree node holding this block */
+       unsigned int base_reg; /* base register handled by this block */
+       unsigned int word_size; /* number of bytes needed to represent the register index */
+       void *block; /* block of adjacent registers */
+       unsigned int blklen; /* number of registers available in the block */
 } __attribute__ ((packed));
 
 struct snd_soc_rbtree_ctx {
        struct rb_root root;
+       struct snd_soc_rbtree_node *cached_rbnode;
 };
 
+static inline void snd_soc_rbtree_get_base_top_reg(
+       struct snd_soc_rbtree_node *rbnode,
+       unsigned int *base, unsigned int *top)
+{
+       *base = rbnode->base_reg;
+       *top = rbnode->base_reg + rbnode->blklen - 1;
+}
+
+static unsigned int snd_soc_rbtree_get_register(
+       struct snd_soc_rbtree_node *rbnode, unsigned int idx)
+{
+       unsigned int val;
+
+       switch (rbnode->word_size) {
+       case 1: {
+               u8 *p = rbnode->block;
+               val = p[idx];
+               return val;
+       }
+       case 2: {
+               u16 *p = rbnode->block;
+               val = p[idx];
+               return val;
+       }
+       default:
+               BUG();
+               break;
+       }
+       return -1;
+}
+
+static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
+                                       unsigned int idx, unsigned int val)
+{
+       switch (rbnode->word_size) {
+       case 1: {
+               u8 *p = rbnode->block;
+               p[idx] = val;
+               break;
+       }
+       case 2: {
+               u16 *p = rbnode->block;
+               p[idx] = val;
+               break;
+       }
+       default:
+               BUG();
+               break;
+       }
+}
+
 static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
        struct rb_root *root, unsigned int reg)
 {
        struct rb_node *node;
        struct snd_soc_rbtree_node *rbnode;
+       unsigned int base_reg, top_reg;
 
        node = root->rb_node;
        while (node) {
                rbnode = container_of(node, struct snd_soc_rbtree_node, node);
-               if (rbnode->reg < reg)
-                       node = node->rb_left;
-               else if (rbnode->reg > reg)
-                       node = node->rb_right;
-               else
+               snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+               if (reg >= base_reg && reg <= top_reg)
                        return rbnode;
+               else if (reg > top_reg)
+                       node = node->rb_right;
+               else if (reg < base_reg)
+                       node = node->rb_left;
        }
 
        return NULL;
@@ -518,19 +157,28 @@ static int snd_soc_rbtree_insert(struct rb_root *root,
 {
        struct rb_node **new, *parent;
        struct snd_soc_rbtree_node *rbnode_tmp;
+       unsigned int base_reg_tmp, top_reg_tmp;
+       unsigned int base_reg;
 
        parent = NULL;
        new = &root->rb_node;
        while (*new) {
                rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
                                          node);
+               /* base and top registers of the current rbnode */
+               snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
+                                               &top_reg_tmp);
+               /* base register of the rbnode to be added */
+               base_reg = rbnode->base_reg;
                parent = *new;
-               if (rbnode_tmp->reg < rbnode->reg)
-                       new = &((*new)->rb_left);
-               else if (rbnode_tmp->reg > rbnode->reg)
-                       new = &((*new)->rb_right);
-               else
+               /* if this register has already been inserted, just return */
+               if (base_reg >= base_reg_tmp &&
+                   base_reg <= top_reg_tmp)
                        return 0;
+               else if (base_reg > top_reg_tmp)
+                       new = &((*new)->rb_right);
+               else if (base_reg < base_reg_tmp)
+                       new = &((*new)->rb_left);
        }
 
        /* insert the node into the rbtree */
@@ -545,58 +193,146 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
        struct snd_soc_rbtree_ctx *rbtree_ctx;
        struct rb_node *node;
        struct snd_soc_rbtree_node *rbnode;
-       unsigned int val;
+       unsigned int regtmp;
+       unsigned int val, def;
        int ret;
+       int i;
 
        rbtree_ctx = codec->reg_cache;
        for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
                rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
-               if (rbnode->value == rbnode->defval)
-                       continue;
-               WARN_ON(codec->writable_register &&
-                       codec->writable_register(codec, rbnode->reg));
-               ret = snd_soc_cache_read(codec, rbnode->reg, &val);
-               if (ret)
-                       return ret;
-               codec->cache_bypass = 1;
-               ret = snd_soc_write(codec, rbnode->reg, val);
-               codec->cache_bypass = 0;
-               if (ret)
-                       return ret;
-               dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
-                       rbnode->reg, val);
+               for (i = 0; i < rbnode->blklen; ++i) {
+                       regtmp = rbnode->base_reg + i;
+                       WARN_ON(codec->writable_register &&
+                               codec->writable_register(codec, regtmp));
+                       val = snd_soc_rbtree_get_register(rbnode, i);
+                       def = snd_soc_get_cache_val(codec->reg_def_copy, i,
+                                                   rbnode->word_size);
+                       if (val == def)
+                               continue;
+
+                       codec->cache_bypass = 1;
+                       ret = snd_soc_write(codec, regtmp, val);
+                       codec->cache_bypass = 0;
+                       if (ret)
+                               return ret;
+                       dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
+                               regtmp, val);
+               }
        }
 
        return 0;
 }
 
+static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
+                                         unsigned int pos, unsigned int reg,
+                                         unsigned int value)
+{
+       u8 *blk;
+
+       blk = krealloc(rbnode->block,
+                      (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
+       if (!blk)
+               return -ENOMEM;
+
+       /* insert the register value in the correct place in the rbnode block */
+       memmove(blk + (pos + 1) * rbnode->word_size,
+               blk + pos * rbnode->word_size,
+               (rbnode->blklen - pos) * rbnode->word_size);
+
+       /* update the rbnode block, its size and the base register */
+       rbnode->block = blk;
+       rbnode->blklen++;
+       if (!pos)
+               rbnode->base_reg = reg;
+
+       snd_soc_rbtree_set_register(rbnode, pos, value);
+       return 0;
+}
+
 static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
                                      unsigned int reg, unsigned int value)
 {
        struct snd_soc_rbtree_ctx *rbtree_ctx;
-       struct snd_soc_rbtree_node *rbnode;
+       struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
+       struct rb_node *node;
+       unsigned int val;
+       unsigned int reg_tmp;
+       unsigned int base_reg, top_reg;
+       unsigned int pos;
+       int i;
+       int ret;
 
        rbtree_ctx = codec->reg_cache;
+       /* look up the required register in the cached rbnode */
+       rbnode = rbtree_ctx->cached_rbnode;
+       if (rbnode) {
+               snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+               if (reg >= base_reg && reg <= top_reg) {
+                       reg_tmp = reg - base_reg;
+                       val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+                       if (val == value)
+                               return 0;
+                       snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
+                       return 0;
+               }
+       }
+       /* if we can't locate it in the cached rbnode we'll have
+        * to traverse the rbtree looking for it.
+        */
        rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
        if (rbnode) {
-               if (rbnode->value == value)
+               reg_tmp = reg - rbnode->base_reg;
+               val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+               if (val == value)
                        return 0;
-               rbnode->value = value;
+               snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
+               rbtree_ctx->cached_rbnode = rbnode;
        } else {
                /* bail out early, no need to create the rbnode yet */
                if (!value)
                        return 0;
-               /*
-                * for uninitialized registers whose value is changed
-                * from the default zero, create an rbnode and insert
-                * it into the tree.
+               /* look for an adjacent register to the one we are about to add */
+               for (node = rb_first(&rbtree_ctx->root); node;
+                    node = rb_next(node)) {
+                       rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
+                       for (i = 0; i < rbnode_tmp->blklen; ++i) {
+                               reg_tmp = rbnode_tmp->base_reg + i;
+                               if (abs(reg_tmp - reg) != 1)
+                                       continue;
+                               /* decide where in the block to place our register */
+                               if (reg_tmp + 1 == reg)
+                                       pos = i + 1;
+                               else
+                                       pos = i;
+                               ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
+                                                                    reg, value);
+                               if (ret)
+                                       return ret;
+                               rbtree_ctx->cached_rbnode = rbnode_tmp;
+                               return 0;
+                       }
+               }
+               /* we did not manage to find a place to insert it in an existing
+                * block so create a new rbnode with a single register in its block.
+                * This block will get populated further if any other adjacent
+                * registers get modified in the future.
                 */
                rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
                if (!rbnode)
                        return -ENOMEM;
-               rbnode->reg = reg;
-               rbnode->value = value;
+               rbnode->blklen = 1;
+               rbnode->base_reg = reg;
+               rbnode->word_size = codec->driver->reg_word_size;
+               rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
+                                       GFP_KERNEL);
+               if (!rbnode->block) {
+                       kfree(rbnode);
+                       return -ENOMEM;
+               }
+               snd_soc_rbtree_set_register(rbnode, 0, value);
                snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
+               rbtree_ctx->cached_rbnode = rbnode;
        }
 
        return 0;
@@ -607,11 +343,28 @@ static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
 {
        struct snd_soc_rbtree_ctx *rbtree_ctx;
        struct snd_soc_rbtree_node *rbnode;
+       unsigned int base_reg, top_reg;
+       unsigned int reg_tmp;
 
        rbtree_ctx = codec->reg_cache;
+       /* look up the required register in the cached rbnode */
+       rbnode = rbtree_ctx->cached_rbnode;
+       if (rbnode) {
+               snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+               if (reg >= base_reg && reg <= top_reg) {
+                       reg_tmp = reg - base_reg;
+                       *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+                       return 0;
+               }
+       }
+       /* if we can't locate it in the cached rbnode we'll have
+        * to traverse the rbtree looking for it.
+        */
        rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
        if (rbnode) {
-               *value = rbnode->value;
+               reg_tmp = reg - rbnode->base_reg;
+               *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+               rbtree_ctx->cached_rbnode = rbnode;
        } else {
                /* uninitialized registers default to 0 */
                *value = 0;
@@ -637,6 +390,7 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
                rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
                next = rb_next(&rbtree_node->node);
                rb_erase(&rbtree_node->node, &rbtree_ctx->root);
+               kfree(rbtree_node->block);
                kfree(rbtree_node);
        }
 
@@ -649,10 +403,9 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
 
 static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
 {
-       struct snd_soc_rbtree_node *rbtree_node;
        struct snd_soc_rbtree_ctx *rbtree_ctx;
-       unsigned int val;
        unsigned int word_size;
+       unsigned int val;
        int i;
        int ret;
 
@@ -662,32 +415,27 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
 
        rbtree_ctx = codec->reg_cache;
        rbtree_ctx->root = RB_ROOT;
+       rbtree_ctx->cached_rbnode = NULL;
 
        if (!codec->reg_def_copy)
                return 0;
 
-       /*
-        * populate the rbtree with the initialized registers.  All other
-        * registers will be inserted when they are first modified.
-        */
        word_size = codec->driver->reg_word_size;
        for (i = 0; i < codec->driver->reg_cache_size; ++i) {
-               val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size);
+               val = snd_soc_get_cache_val(codec->reg_def_copy, i,
+                                           word_size);
                if (!val)
                        continue;
-               rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL);
-               if (!rbtree_node) {
-                       ret = -ENOMEM;
-                       snd_soc_cache_exit(codec);
-                       break;
-               }
-               rbtree_node->reg = i;
-               rbtree_node->value = val;
-               rbtree_node->defval = val;
-               snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
+               ret = snd_soc_rbtree_cache_write(codec, i, val);
+               if (ret)
+                       goto err;
        }
 
        return 0;
+
+err:
+       snd_soc_cache_exit(codec);
+       return ret;
 }
 
 #ifdef CONFIG_SND_SOC_CACHE_LZO
index b194be0..e44267f 100644 (file)
@@ -44,7 +44,6 @@
 
 #define NAME_SIZE      32
 
-static DEFINE_MUTEX(pcm_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
 
 #ifdef CONFIG_DEBUG_FS
@@ -58,7 +57,7 @@ static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
 
-static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
+int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
 
 /*
  * This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -485,552 +484,6 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
 }
 #endif
 
-static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       if (!codec_dai->driver->symmetric_rates &&
-           !cpu_dai->driver->symmetric_rates &&
-           !rtd->dai_link->symmetric_rates)
-               return 0;
-
-       /* This can happen if multiple streams are starting simultaneously -
-        * the second can need to get its constraints before the first has
-        * picked a rate.  Complain and allow the application to carry on.
-        */
-       if (!rtd->rate) {
-               dev_warn(&rtd->dev,
-                        "Not enforcing symmetric_rates due to race\n");
-               return 0;
-       }
-
-       dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", rtd->rate);
-
-       ret = snd_pcm_hw_constraint_minmax(substream->runtime,
-                                          SNDRV_PCM_HW_PARAM_RATE,
-                                          rtd->rate, rtd->rate);
-       if (ret < 0) {
-               dev_err(&rtd->dev,
-                       "Unable to apply rate symmetry constraint: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-/*
- * Called by ALSA when a PCM substream is opened, the runtime->hw record is
- * then initialized and any private data can be allocated. This also calls
- * startup for the cpu DAI, platform, machine and codec DAI.
- */
-static int soc_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
-       struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
-       int ret = 0;
-
-       mutex_lock(&pcm_mutex);
-
-       /* startup the audio subsystem */
-       if (cpu_dai->driver->ops->startup) {
-               ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: can't open interface %s\n",
-                               cpu_dai->name);
-                       goto out;
-               }
-       }
-
-       if (platform->driver->ops && platform->driver->ops->open) {
-               ret = platform->driver->ops->open(substream);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
-                       goto platform_err;
-               }
-       }
-
-       if (codec_dai->driver->ops->startup) {
-               ret = codec_dai->driver->ops->startup(substream, codec_dai);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: can't open codec %s\n",
-                               codec_dai->name);
-                       goto codec_dai_err;
-               }
-       }
-
-       if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
-               ret = rtd->dai_link->ops->startup(substream);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
-                       goto machine_err;
-               }
-       }
-
-       /* Check that the codec and cpu DAIs are compatible */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               runtime->hw.rate_min =
-                       max(codec_dai_drv->playback.rate_min,
-                           cpu_dai_drv->playback.rate_min);
-               runtime->hw.rate_max =
-                       min(codec_dai_drv->playback.rate_max,
-                           cpu_dai_drv->playback.rate_max);
-               runtime->hw.channels_min =
-                       max(codec_dai_drv->playback.channels_min,
-                               cpu_dai_drv->playback.channels_min);
-               runtime->hw.channels_max =
-                       min(codec_dai_drv->playback.channels_max,
-                               cpu_dai_drv->playback.channels_max);
-               runtime->hw.formats =
-                       codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
-               runtime->hw.rates =
-                       codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
-               if (codec_dai_drv->playback.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai_drv->playback.rates;
-               if (cpu_dai_drv->playback.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai_drv->playback.rates;
-       } else {
-               runtime->hw.rate_min =
-                       max(codec_dai_drv->capture.rate_min,
-                           cpu_dai_drv->capture.rate_min);
-               runtime->hw.rate_max =
-                       min(codec_dai_drv->capture.rate_max,
-                           cpu_dai_drv->capture.rate_max);
-               runtime->hw.channels_min =
-                       max(codec_dai_drv->capture.channels_min,
-                               cpu_dai_drv->capture.channels_min);
-               runtime->hw.channels_max =
-                       min(codec_dai_drv->capture.channels_max,
-                               cpu_dai_drv->capture.channels_max);
-               runtime->hw.formats =
-                       codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
-               runtime->hw.rates =
-                       codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
-               if (codec_dai_drv->capture.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai_drv->capture.rates;
-               if (cpu_dai_drv->capture.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai_drv->capture.rates;
-       }
-
-       ret = -EINVAL;
-       snd_pcm_limit_hw_rates(runtime);
-       if (!runtime->hw.rates) {
-               printk(KERN_ERR "asoc: %s <-> %s No matching rates\n",
-                       codec_dai->name, cpu_dai->name);
-               goto config_err;
-       }
-       if (!runtime->hw.formats) {
-               printk(KERN_ERR "asoc: %s <-> %s No matching formats\n",
-                       codec_dai->name, cpu_dai->name);
-               goto config_err;
-       }
-       if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
-           runtime->hw.channels_min > runtime->hw.channels_max) {
-               printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
-                               codec_dai->name, cpu_dai->name);
-               goto config_err;
-       }
-
-       /* Symmetry only applies if we've already got an active stream. */
-       if (cpu_dai->active || codec_dai->active) {
-               ret = soc_pcm_apply_symmetry(substream);
-               if (ret != 0)
-                       goto config_err;
-       }
-
-       pr_debug("asoc: %s <-> %s info:\n",
-                       codec_dai->name, cpu_dai->name);
-       pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
-       pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
-                runtime->hw.channels_max);
-       pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
-                runtime->hw.rate_max);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               cpu_dai->playback_active++;
-               codec_dai->playback_active++;
-       } else {
-               cpu_dai->capture_active++;
-               codec_dai->capture_active++;
-       }
-       cpu_dai->active++;
-       codec_dai->active++;
-       rtd->codec->active++;
-       mutex_unlock(&pcm_mutex);
-       return 0;
-
-config_err:
-       if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
-               rtd->dai_link->ops->shutdown(substream);
-
-machine_err:
-       if (codec_dai->driver->ops->shutdown)
-               codec_dai->driver->ops->shutdown(substream, codec_dai);
-
-codec_dai_err:
-       if (platform->driver->ops && platform->driver->ops->close)
-               platform->driver->ops->close(substream);
-
-platform_err:
-       if (cpu_dai->driver->ops->shutdown)
-               cpu_dai->driver->ops->shutdown(substream, cpu_dai);
-out:
-       mutex_unlock(&pcm_mutex);
-       return ret;
-}
-
-/*
- * Power down the audio subsystem pmdown_time msecs after close is called.
- * This is to ensure there are no pops or clicks in between any music tracks
- * due to DAPM power cycling.
- */
-static void close_delayed_work(struct work_struct *work)
-{
-       struct snd_soc_pcm_runtime *rtd =
-                       container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-       mutex_lock(&pcm_mutex);
-
-       pr_debug("pop wq checking: %s status: %s waiting: %s\n",
-                codec_dai->driver->playback.stream_name,
-                codec_dai->playback_active ? "active" : "inactive",
-                codec_dai->pop_wait ? "yes" : "no");
-
-       /* are we waiting on this codec DAI stream */
-       if (codec_dai->pop_wait == 1) {
-               codec_dai->pop_wait = 0;
-               snd_soc_dapm_stream_event(rtd,
-                       codec_dai->driver->playback.stream_name,
-                       SND_SOC_DAPM_STREAM_STOP);
-       }
-
-       mutex_unlock(&pcm_mutex);
-}
-
-/*
- * Called by ALSA when a PCM substream is closed. Private data can be
- * freed here. The cpu DAI, codec DAI, machine and platform are also
- * shutdown.
- */
-static int soc_codec_close(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_codec *codec = rtd->codec;
-
-       mutex_lock(&pcm_mutex);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               cpu_dai->playback_active--;
-               codec_dai->playback_active--;
-       } else {
-               cpu_dai->capture_active--;
-               codec_dai->capture_active--;
-       }
-
-       cpu_dai->active--;
-       codec_dai->active--;
-       codec->active--;
-
-       /* Muting the DAC suppresses artifacts caused during digital
-        * shutdown, for example from stopping clocks.
-        */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               snd_soc_dai_digital_mute(codec_dai, 1);
-
-       if (cpu_dai->driver->ops->shutdown)
-               cpu_dai->driver->ops->shutdown(substream, cpu_dai);
-
-       if (codec_dai->driver->ops->shutdown)
-               codec_dai->driver->ops->shutdown(substream, codec_dai);
-
-       if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
-               rtd->dai_link->ops->shutdown(substream);
-
-       if (platform->driver->ops && platform->driver->ops->close)
-               platform->driver->ops->close(substream);
-       cpu_dai->runtime = NULL;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               /* start delayed pop wq here for playback streams */
-               codec_dai->pop_wait = 1;
-               schedule_delayed_work(&rtd->delayed_work,
-                       msecs_to_jiffies(rtd->pmdown_time));
-       } else {
-               /* capture streams can be powered down now */
-               snd_soc_dapm_stream_event(rtd,
-                       codec_dai->driver->capture.stream_name,
-                       SND_SOC_DAPM_STREAM_STOP);
-       }
-
-       mutex_unlock(&pcm_mutex);
-       return 0;
-}
-
-/*
- * Called by ALSA when the PCM substream is prepared, can set format, sample
- * rate, etc.  This function is non atomic and can be called multiple times,
- * it can refer to the runtime info.
- */
-static int soc_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret = 0;
-
-       mutex_lock(&pcm_mutex);
-
-       if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
-               ret = rtd->dai_link->ops->prepare(substream);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: machine prepare error\n");
-                       goto out;
-               }
-       }
-
-       if (platform->driver->ops && platform->driver->ops->prepare) {
-               ret = platform->driver->ops->prepare(substream);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: platform prepare error\n");
-                       goto out;
-               }
-       }
-
-       if (codec_dai->driver->ops->prepare) {
-               ret = codec_dai->driver->ops->prepare(substream, codec_dai);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: codec DAI prepare error\n");
-                       goto out;
-               }
-       }
-
-       if (cpu_dai->driver->ops->prepare) {
-               ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: cpu DAI prepare error\n");
-                       goto out;
-               }
-       }
-
-       /* cancel any delayed stream shutdown that is pending */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
-           codec_dai->pop_wait) {
-               codec_dai->pop_wait = 0;
-               cancel_delayed_work(&rtd->delayed_work);
-       }
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               snd_soc_dapm_stream_event(rtd,
-                                         codec_dai->driver->playback.stream_name,
-                                         SND_SOC_DAPM_STREAM_START);
-       else
-               snd_soc_dapm_stream_event(rtd,
-                                         codec_dai->driver->capture.stream_name,
-                                         SND_SOC_DAPM_STREAM_START);
-
-       snd_soc_dai_digital_mute(codec_dai, 0);
-
-out:
-       mutex_unlock(&pcm_mutex);
-       return ret;
-}
-
-/*
- * Called by ALSA when the hardware params are set by application. This
- * function can also be called multiple times and can allocate buffers
- * (using snd_pcm_lib_* ). It's non-atomic.
- */
-static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret = 0;
-
-       mutex_lock(&pcm_mutex);
-
-       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
-               ret = rtd->dai_link->ops->hw_params(substream, params);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: machine hw_params failed\n");
-                       goto out;
-               }
-       }
-
-       if (codec_dai->driver->ops->hw_params) {
-               ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: can't set codec %s hw params\n",
-                               codec_dai->name);
-                       goto codec_err;
-               }
-       }
-
-       if (cpu_dai->driver->ops->hw_params) {
-               ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: interface %s hw params failed\n",
-                               cpu_dai->name);
-                       goto interface_err;
-               }
-       }
-
-       if (platform->driver->ops && platform->driver->ops->hw_params) {
-               ret = platform->driver->ops->hw_params(substream, params);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: platform %s hw params failed\n",
-                               platform->name);
-                       goto platform_err;
-               }
-       }
-
-       rtd->rate = params_rate(params);
-
-out:
-       mutex_unlock(&pcm_mutex);
-       return ret;
-
-platform_err:
-       if (cpu_dai->driver->ops->hw_free)
-               cpu_dai->driver->ops->hw_free(substream, cpu_dai);
-
-interface_err:
-       if (codec_dai->driver->ops->hw_free)
-               codec_dai->driver->ops->hw_free(substream, codec_dai);
-
-codec_err:
-       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
-               rtd->dai_link->ops->hw_free(substream);
-
-       mutex_unlock(&pcm_mutex);
-       return ret;
-}
-
-/*
- * Frees resources allocated by hw_params, can be called multiple times
- */
-static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_codec *codec = rtd->codec;
-
-       mutex_lock(&pcm_mutex);
-
-       /* apply codec digital mute */
-       if (!codec->active)
-               snd_soc_dai_digital_mute(codec_dai, 1);
-
-       /* free any machine hw params */
-       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
-               rtd->dai_link->ops->hw_free(substream);
-
-       /* free any DMA resources */
-       if (platform->driver->ops && platform->driver->ops->hw_free)
-               platform->driver->ops->hw_free(substream);
-
-       /* now free hw params for the DAIs  */
-       if (codec_dai->driver->ops->hw_free)
-               codec_dai->driver->ops->hw_free(substream, codec_dai);
-
-       if (cpu_dai->driver->ops->hw_free)
-               cpu_dai->driver->ops->hw_free(substream, cpu_dai);
-
-       mutex_unlock(&pcm_mutex);
-       return 0;
-}
-
-static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       if (codec_dai->driver->ops->trigger) {
-               ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
-               if (ret < 0)
-                       return ret;
-       }
-
-       if (platform->driver->ops && platform->driver->ops->trigger) {
-               ret = platform->driver->ops->trigger(substream, cmd);
-               if (ret < 0)
-                       return ret;
-       }
-
-       if (cpu_dai->driver->ops->trigger) {
-               ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
-               if (ret < 0)
-                       return ret;
-       }
-       return 0;
-}
-
-/*
- * soc level wrapper for pointer callback
- * If cpu_dai, codec_dai, platform driver has the delay callback, than
- * the runtime->delay will be updated accordingly.
- */
-static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       snd_pcm_uframes_t offset = 0;
-       snd_pcm_sframes_t delay = 0;
-
-       if (platform->driver->ops && platform->driver->ops->pointer)
-               offset = platform->driver->ops->pointer(substream);
-
-       if (cpu_dai->driver->ops->delay)
-               delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
-
-       if (codec_dai->driver->ops->delay)
-               delay += codec_dai->driver->ops->delay(substream, codec_dai);
-
-       if (platform->driver->delay)
-               delay += platform->driver->delay(substream, codec_dai);
-
-       runtime->delay = delay;
-
-       return offset;
-}
-
-/* ASoC PCM operations */
-static struct snd_pcm_ops soc_pcm_ops = {
-       .open           = soc_pcm_open,
-       .close          = soc_codec_close,
-       .hw_params      = soc_pcm_hw_params,
-       .hw_free        = soc_pcm_hw_free,
-       .prepare        = soc_pcm_prepare,
-       .trigger        = soc_pcm_trigger,
-       .pointer        = soc_pcm_pointer,
-};
-
 #ifdef CONFIG_PM_SLEEP
 /* powers down audio subsystem for suspend */
 int snd_soc_suspend(struct device *dev)
@@ -1256,7 +709,7 @@ static void soc_resume_deferred(struct work_struct *work)
 int snd_soc_resume(struct device *dev)
 {
        struct snd_soc_card *card = dev_get_drvdata(dev);
-       int i;
+       int i, ac97_control = 0;
 
        /* AC97 devices might have other drivers hanging off them so
         * need to resume immediately.  Other drivers don't have that
@@ -1265,14 +718,15 @@ int snd_soc_resume(struct device *dev)
         */
        for (i = 0; i < card->num_rtd; i++) {
                struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
-               if (cpu_dai->driver->ac97_control) {
-                       dev_dbg(dev, "Resuming AC97 immediately\n");
-                       soc_resume_deferred(&card->deferred_resume_work);
-               } else {
-                       dev_dbg(dev, "Scheduling resume work\n");
-                       if (!schedule_work(&card->deferred_resume_work))
-                               dev_err(dev, "resume work item may be lost\n");
-               }
+               ac97_control |= cpu_dai->driver->ac97_control;
+       }
+       if (ac97_control) {
+               dev_dbg(dev, "Resuming AC97 immediately\n");
+               soc_resume_deferred(&card->deferred_resume_work);
+       } else {
+               dev_dbg(dev, "Scheduling resume work\n");
+               if (!schedule_work(&card->deferred_resume_work))
+                       dev_err(dev, "resume work item may be lost\n");
        }
 
        return 0;
@@ -1393,7 +847,7 @@ static void soc_remove_codec(struct snd_soc_codec *codec)
        module_put(codec->dev->driver->owner);
 }
 
-static void soc_remove_dai_link(struct snd_soc_card *card, int num)
+static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
 {
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        struct snd_soc_codec *codec = rtd->codec;
@@ -1410,7 +864,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
        }
 
        /* remove the CODEC DAI */
-       if (codec_dai && codec_dai->probed) {
+       if (codec_dai && codec_dai->probed &&
+                       codec_dai->driver->remove_order == order) {
                if (codec_dai->driver->remove) {
                        err = codec_dai->driver->remove(codec_dai);
                        if (err < 0)
@@ -1421,7 +876,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
        }
 
        /* remove the platform */
-       if (platform && platform->probed) {
+       if (platform && platform->probed &&
+                       platform->driver->remove_order == order) {
                if (platform->driver->remove) {
                        err = platform->driver->remove(platform);
                        if (err < 0)
@@ -1433,11 +889,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
        }
 
        /* remove the CODEC */
-       if (codec && codec->probed)
+       if (codec && codec->probed &&
+                       codec->driver->remove_order == order)
                soc_remove_codec(codec);
 
        /* remove the cpu_dai */
-       if (cpu_dai && cpu_dai->probed) {
+       if (cpu_dai && cpu_dai->probed &&
+                       cpu_dai->driver->remove_order == order) {
                if (cpu_dai->driver->remove) {
                        err = cpu_dai->driver->remove(cpu_dai);
                        if (err < 0)
@@ -1451,11 +909,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
 
 static void soc_remove_dai_links(struct snd_soc_card *card)
 {
-       int i;
-
-       for (i = 0; i < card->num_rtd; i++)
-               soc_remove_dai_link(card, i);
+       int dai, order;
 
+       for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+                       order++) {
+               for (dai = 0; dai < card->num_rtd; dai++)
+                       soc_remove_dai_link(card, dai, order);
+       }
        card->num_rtd = 0;
 }
 
@@ -1526,6 +986,52 @@ err_probe:
        return ret;
 }
 
+static int soc_probe_platform(struct snd_soc_card *card,
+                          struct snd_soc_platform *platform)
+{
+       int ret = 0;
+       const struct snd_soc_platform_driver *driver = platform->driver;
+
+       platform->card = card;
+       platform->dapm.card = card;
+
+       if (!try_module_get(platform->dev->driver->owner))
+               return -ENODEV;
+
+       if (driver->dapm_widgets)
+               snd_soc_dapm_new_controls(&platform->dapm,
+                       driver->dapm_widgets, driver->num_dapm_widgets);
+
+       if (driver->probe) {
+               ret = driver->probe(platform);
+               if (ret < 0) {
+                       dev_err(platform->dev,
+                               "asoc: failed to probe platform %s: %d\n",
+                               platform->name, ret);
+                       goto err_probe;
+               }
+       }
+
+       if (driver->controls)
+               snd_soc_add_platform_controls(platform, driver->controls,
+                                    driver->num_controls);
+       if (driver->dapm_routes)
+               snd_soc_dapm_add_routes(&platform->dapm, driver->dapm_routes,
+                                       driver->num_dapm_routes);
+
+       /* mark platform as probed and add to card platform list */
+       platform->probed = 1;
+       list_add(&platform->card_list, &card->platform_dev_list);
+       list_add(&platform->dapm.list, &card->dapm_list);
+
+       return 0;
+
+err_probe:
+       module_put(platform->dev->driver->owner);
+
+       return ret;
+}
+
 static void rtd_release(struct device *dev) {}
 
 static int soc_post_component_init(struct snd_soc_card *card,
@@ -1572,6 +1078,7 @@ static int soc_post_component_init(struct snd_soc_card *card,
        rtd->dev.parent = card->dev;
        rtd->dev.release = rtd_release;
        rtd->dev.init_name = name;
+       mutex_init(&rtd->pcm_mutex);
        ret = device_register(&rtd->dev);
        if (ret < 0) {
                dev_err(card->dev,
@@ -1596,7 +1103,7 @@ static int soc_post_component_init(struct snd_soc_card *card,
        return 0;
 }
 
-static int soc_probe_dai_link(struct snd_soc_card *card, int num)
+static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
 {
        struct snd_soc_dai_link *dai_link = &card->dai_link[num];
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
@@ -1605,7 +1112,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
        struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
        int ret;
 
-       dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num);
+       dev_dbg(card->dev, "probe %s dai link %d late %d\n",
+                       card->name, num, order);
 
        /* config components */
        codec_dai->codec = codec;
@@ -1617,7 +1125,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
        rtd->pmdown_time = pmdown_time;
 
        /* probe the cpu_dai */
-       if (!cpu_dai->probed) {
+       if (!cpu_dai->probed &&
+                       cpu_dai->driver->probe_order == order) {
                if (!try_module_get(cpu_dai->dev->driver->owner))
                        return -ENODEV;
 
@@ -1636,33 +1145,23 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
        }
 
        /* probe the CODEC */
-       if (!codec->probed) {
+       if (!codec->probed &&
+                       codec->driver->probe_order == order) {
                ret = soc_probe_codec(card, codec);
                if (ret < 0)
                        return ret;
        }
 
        /* probe the platform */
-       if (!platform->probed) {
-               if (!try_module_get(platform->dev->driver->owner))
-                       return -ENODEV;
-
-               if (platform->driver->probe) {
-                       ret = platform->driver->probe(platform);
-                       if (ret < 0) {
-                               printk(KERN_ERR "asoc: failed to probe platform %s\n",
-                                               platform->name);
-                               module_put(platform->dev->driver->owner);
-                               return ret;
-                       }
-               }
-               /* mark platform as probed and add to card platform list */
-               platform->probed = 1;
-               list_add(&platform->card_list, &card->platform_dev_list);
+       if (!platform->probed &&
+                       platform->driver->probe_order == order) {
+               ret = soc_probe_platform(card, platform);
+               if (ret < 0)
+                       return ret;
        }
 
        /* probe the CODEC DAI */
-       if (!codec_dai->probed) {
+       if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
                if (codec_dai->driver->probe) {
                        ret = codec_dai->driver->probe(codec_dai);
                        if (ret < 0) {
@@ -1677,8 +1176,9 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
                list_add(&codec_dai->card_list, &card->dai_dev_list);
        }
 
-       /* DAPM dai link stream work */
-       INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+       /* complete DAI probe during last probe */
+       if (order != SND_SOC_COMP_ORDER_LAST)
+               return 0;
 
        ret = soc_post_component_init(card, codec, num, 0);
        if (ret)
@@ -1817,7 +1317,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        struct snd_soc_codec *codec;
        struct snd_soc_codec_conf *codec_conf;
        enum snd_soc_compress_type compress_type;
-       int ret, i;
+       int ret, i, order;
 
        mutex_lock(&card->mutex);
 
@@ -1895,12 +1395,16 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                        goto card_probe_error;
        }
 
-       for (i = 0; i < card->num_links; i++) {
-               ret = soc_probe_dai_link(card, i);
-               if (ret < 0) {
-                       pr_err("asoc: failed to instantiate card %s: %d\n",
+       /* early DAI link probe */
+       for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+                       order++) {
+               for (i = 0; i < card->num_links; i++) {
+                       ret = soc_probe_dai_link(card, i, order);
+                       if (ret < 0) {
+                               pr_err("asoc: failed to instantiate card %s: %d\n",
                               card->name, ret);
-                       goto probe_dai_err;
+                               goto probe_dai_err;
+                       }
                }
        }
 
@@ -2096,67 +1600,6 @@ static struct platform_driver soc_driver = {
        .remove         = soc_remove,
 };
 
-/* create a new pcm */
-static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_pcm *pcm;
-       char new_name[64];
-       int ret = 0, playback = 0, capture = 0;
-
-       /* check client and interface hw capabilities */
-       snprintf(new_name, sizeof(new_name), "%s %s-%d",
-                       rtd->dai_link->stream_name, codec_dai->name, num);
-
-       if (codec_dai->driver->playback.channels_min)
-               playback = 1;
-       if (codec_dai->driver->capture.channels_min)
-               capture = 1;
-
-       dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
-       ret = snd_pcm_new(rtd->card->snd_card, new_name,
-                       num, playback, capture, &pcm);
-       if (ret < 0) {
-               printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
-               return ret;
-       }
-
-       rtd->pcm = pcm;
-       pcm->private_data = rtd;
-       if (platform->driver->ops) {
-               soc_pcm_ops.mmap = platform->driver->ops->mmap;
-               soc_pcm_ops.pointer = platform->driver->ops->pointer;
-               soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
-               soc_pcm_ops.copy = platform->driver->ops->copy;
-               soc_pcm_ops.silence = platform->driver->ops->silence;
-               soc_pcm_ops.ack = platform->driver->ops->ack;
-               soc_pcm_ops.page = platform->driver->ops->page;
-       }
-
-       if (playback)
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
-
-       if (capture)
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
-
-       if (platform->driver->pcm_new) {
-               ret = platform->driver->pcm_new(rtd->card->snd_card,
-                                               codec_dai, pcm);
-               if (ret < 0) {
-                       pr_err("asoc: platform pcm constructor failed\n");
-                       return ret;
-               }
-       }
-
-       pcm->private_free = platform->driver->pcm_free;
-       printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
-               cpu_dai->name);
-       return ret;
-}
-
 /**
  * snd_soc_codec_volatile_register: Report if a register is volatile.
  *
@@ -2211,6 +1654,38 @@ int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register);
 
+int snd_soc_platform_read(struct snd_soc_platform *platform,
+                                       unsigned int reg)
+{
+       unsigned int ret;
+
+       if (!platform->driver->read) {
+               dev_err(platform->dev, "platform has no read back\n");
+               return -1;
+       }
+
+       ret = platform->driver->read(platform, reg);
+       dev_dbg(platform->dev, "read %x => %x\n", reg, ret);
+       trace_snd_soc_preg_read(platform, reg, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_platform_read);
+
+int snd_soc_platform_write(struct snd_soc_platform *platform,
+                                        unsigned int reg, unsigned int val)
+{
+       if (!platform->driver->write) {
+               dev_err(platform->dev, "platform has no write back\n");
+               return -1;
+       }
+
+       dev_dbg(platform->dev, "write %x = %x\n", reg, val);
+       trace_snd_soc_preg_write(platform, reg, val);
+       return platform->driver->write(platform, reg, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_platform_write);
+
 /**
  * snd_soc_new_ac97_codec - initailise AC97 device
  * @codec: audio codec
@@ -2323,7 +1798,7 @@ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
                return ret;
 
        old = ret;
-       new = (old & ~mask) | value;
+       new = (old & ~mask) | (value & mask);
        change = old != new;
        if (change) {
                ret = snd_soc_write(codec, reg, new);
@@ -2489,6 +1964,36 @@ int snd_soc_add_controls(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_add_controls);
 
+/**
+ * snd_soc_add_platform_controls - add an array of controls to a platform.
+ * Convienience function to add a list of controls.
+ *
+ * @platform: platform to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
+       const struct snd_kcontrol_new *controls, int num_controls)
+{
+       struct snd_card *card = platform->card->snd_card;
+       int err, i;
+
+       for (i = 0; i < num_controls; i++) {
+               const struct snd_kcontrol_new *control = &controls[i];
+               err = snd_ctl_add(card, snd_soc_cnew(control, platform,
+                               control->name, NULL));
+               if (err < 0) {
+                       dev_err(platform->dev, "Failed to add %s %d\n",control->name, err);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
+
 /**
  * snd_soc_info_enum_double - enumerated double mixer info callback
  * @kcontrol: mixer control
@@ -3633,6 +3138,8 @@ int snd_soc_register_platform(struct device *dev,
 
        platform->dev = dev;
        platform->driver = platform_drv;
+       platform->dapm.dev = dev;
+       platform->dapm.platform = platform;
 
        mutex_lock(&client_mutex);
        list_add(&platform->list, &platform_list);
index 32ab7fc..fbfcda0 100644 (file)
@@ -124,6 +124,51 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
        return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
 }
 
+static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
+{
+       if (w->codec)
+               return snd_soc_read(w->codec, reg);
+       else if (w->platform)
+               return snd_soc_platform_read(w->platform, reg);
+
+       dev_err(w->dapm->dev, "no valid widget read method\n");
+       return -1;
+}
+
+static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
+{
+       if (w->codec)
+               return snd_soc_write(w->codec, reg, val);
+       else if (w->platform)
+               return snd_soc_platform_write(w->platform, reg, val);
+
+       dev_err(w->dapm->dev, "no valid widget write method\n");
+       return -1;
+}
+
+static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
+       unsigned short reg, unsigned int mask, unsigned int value)
+{
+       int change;
+       unsigned int old, new;
+       int ret;
+
+       ret = soc_widget_read(w, reg);
+       if (ret < 0)
+               return ret;
+
+       old = ret;
+       new = (old & ~mask) | (value & mask);
+       change = old != new;
+       if (change) {
+               ret = soc_widget_write(w, reg, new);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return change;
+}
+
 /**
  * snd_soc_dapm_set_bias_level - set the bias level for the system
  * @dapm: DAPM context
@@ -139,39 +184,26 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
        struct snd_soc_card *card = dapm->card;
        int ret = 0;
 
-       switch (level) {
-       case SND_SOC_BIAS_ON:
-               dev_dbg(dapm->dev, "Setting full bias\n");
-               break;
-       case SND_SOC_BIAS_PREPARE:
-               dev_dbg(dapm->dev, "Setting bias prepare\n");
-               break;
-       case SND_SOC_BIAS_STANDBY:
-               dev_dbg(dapm->dev, "Setting standby bias\n");
-               break;
-       case SND_SOC_BIAS_OFF:
-               dev_dbg(dapm->dev, "Setting bias off\n");
-               break;
-       default:
-               dev_err(dapm->dev, "Setting invalid bias %d\n", level);
-               return -EINVAL;
-       }
-
        trace_snd_soc_bias_level_start(card, level);
 
        if (card && card->set_bias_level)
-               ret = card->set_bias_level(card, level);
-       if (ret == 0) {
-               if (dapm->codec && dapm->codec->driver->set_bias_level)
-                       ret = dapm->codec->driver->set_bias_level(dapm->codec, level);
+               ret = card->set_bias_level(card, dapm, level);
+       if (ret != 0)
+               goto out;
+
+       if (dapm->codec) {
+               if (dapm->codec->driver->set_bias_level)
+                       ret = dapm->codec->driver->set_bias_level(dapm->codec,
+                                                                 level);
                else
                        dapm->bias_level = level;
        }
-       if (ret == 0) {
-               if (card && card->set_bias_level_post)
-                       ret = card->set_bias_level_post(card, level);
-       }
+       if (ret != 0)
+               goto out;
 
+       if (card && card->set_bias_level_post)
+               ret = card->set_bias_level_post(card, dapm, level);
+out:
        trace_snd_soc_bias_level_done(card, level);
 
        return ret;
@@ -194,7 +226,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                unsigned int mask = (1 << fls(max)) - 1;
                unsigned int invert = mc->invert;
 
-               val = snd_soc_read(w->codec, reg);
+               val = soc_widget_read(w, reg);
                val = (val >> shift) & mask;
 
                if ((invert && !val) || (!invert && val))
@@ -209,8 +241,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                int val, item, bitmask;
 
                for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
-               ;
-               val = snd_soc_read(w->codec, e->reg);
+                       ;
+               val = soc_widget_read(w, e->reg);
                item = (val >> e->shift_l) & (bitmask - 1);
 
                p->connect = 0;
@@ -240,7 +272,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                        w->kcontrol_news[i].private_value;
                int val, item;
 
-               val = snd_soc_read(w->codec, e->reg);
+               val = soc_widget_read(w, e->reg);
                val = (val >> e->shift_l) & e->mask;
                for (item = 0; item < e->max; item++) {
                        if (val == e->values[item])
@@ -606,6 +638,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
        }
 
        list_for_each_entry(path, &widget->sinks, list_source) {
+               if (path->weak)
+                       continue;
+
                if (path->walked)
                        continue;
 
@@ -656,6 +691,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
        }
 
        list_for_each_entry(path, &widget->sources, list_sink) {
+               if (path->weak)
+                       continue;
+
                if (path->walked)
                        continue;
 
@@ -681,7 +719,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
        else
                val = w->off_val;
 
-       snd_soc_update_bits(w->codec, -(w->reg + 1),
+       soc_widget_update_bits(w, -(w->reg + 1),
                            w->mask << w->shift, val << w->shift);
 
        return 0;
@@ -737,6 +775,9 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
 
        /* Check if one of our outputs is connected */
        list_for_each_entry(path, &w->sinks, list_source) {
+               if (path->weak)
+                       continue;
+
                if (path->connected &&
                    !path->connected(path->source, path->sink))
                        continue;
@@ -885,11 +926,17 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
        }
 
        if (reg >= 0) {
+               /* Any widget will do, they should all be updating the
+                * same register.
+                */
+               w = list_first_entry(pending, struct snd_soc_dapm_widget,
+                                    power_list);
+
                pop_dbg(dapm->dev, card->pop_time,
                        "pop test : Applying 0x%x/0x%x to %x in %dms\n",
                        value, mask, reg, card->pop_time);
                pop_wait(card->pop_time);
-               snd_soc_update_bits(dapm->codec, reg, mask, value);
+               soc_widget_update_bits(w, reg, mask, value);
        }
 
        list_for_each_entry(w, pending, power_list) {
@@ -942,7 +989,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
 
                        INIT_LIST_HEAD(&pending);
                        cur_sort = -1;
-                       cur_subseq = -1;
+                       cur_subseq = INT_MIN;
                        cur_reg = SND_SOC_NOPM;
                        cur_dapm = NULL;
                }
@@ -1041,16 +1088,17 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
        struct snd_soc_dapm_context *d = data;
        int ret;
 
-       if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) {
+       /* If we're off and we're not supposed to be go into STANDBY */
+       if (d->bias_level == SND_SOC_BIAS_OFF &&
+           d->target_bias_level != SND_SOC_BIAS_OFF) {
                ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
                if (ret != 0)
                        dev_err(d->dev,
                                "Failed to turn on bias: %d\n", ret);
        }
 
-       /* If we're changing to all on or all off then prepare */
-       if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) ||
-           (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
+       /* Prepare for a STADDBY->ON or ON->STANDBY transition */
+       if (d->bias_level != d->target_bias_level) {
                ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
                if (ret != 0)
                        dev_err(d->dev,
@@ -1067,7 +1115,9 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
        int ret;
 
        /* If we just powered the last thing off drop to standby bias */
-       if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) {
+       if (d->bias_level == SND_SOC_BIAS_PREPARE &&
+           (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
+            d->target_bias_level == SND_SOC_BIAS_OFF)) {
                ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
                if (ret != 0)
                        dev_err(d->dev, "Failed to apply standby bias: %d\n",
@@ -1075,14 +1125,16 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
        }
 
        /* If we're in standby and can support bias off then do that */
-       if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) {
+       if (d->bias_level == SND_SOC_BIAS_STANDBY &&
+           d->target_bias_level == SND_SOC_BIAS_OFF) {
                ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
                if (ret != 0)
                        dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
        }
 
        /* If we just powered up then move to active bias */
-       if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) {
+       if (d->bias_level == SND_SOC_BIAS_PREPARE &&
+           d->target_bias_level == SND_SOC_BIAS_ON) {
                ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
                if (ret != 0)
                        dev_err(d->dev, "Failed to apply active bias: %d\n",
@@ -1107,13 +1159,19 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
        LIST_HEAD(up_list);
        LIST_HEAD(down_list);
        LIST_HEAD(async_domain);
+       enum snd_soc_bias_level bias;
        int power;
 
        trace_snd_soc_dapm_start(card);
 
-       list_for_each_entry(d, &card->dapm_list, list)
-               if (d->n_widgets || d->codec == NULL)
-                       d->dev_power = 0;
+       list_for_each_entry(d, &card->dapm_list, list) {
+               if (d->n_widgets || d->codec == NULL) {
+                       if (d->idle_bias_off)
+                               d->target_bias_level = SND_SOC_BIAS_OFF;
+                       else
+                               d->target_bias_level = SND_SOC_BIAS_STANDBY;
+               }
+       }
 
        /* Check which widgets we need to power and store them in
         * lists indicating if they should be powered up or down.
@@ -1135,8 +1193,27 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                                power = w->power_check(w);
                        else
                                power = 1;
-                       if (power)
-                               w->dapm->dev_power = 1;
+
+                       if (power) {
+                               d = w->dapm;
+
+                               /* Supplies and micbiases only bring
+                                * the context up to STANDBY as unless
+                                * something else is active and
+                                * passing audio they generally don't
+                                * require full power.
+                                */
+                               switch (w->id) {
+                               case snd_soc_dapm_supply:
+                               case snd_soc_dapm_micbias:
+                                       if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
+                                               d->target_bias_level = SND_SOC_BIAS_STANDBY;
+                                       break;
+                               default:
+                                       d->target_bias_level = SND_SOC_BIAS_ON;
+                                       break;
+                               }
+                       }
 
                        if (w->power == power)
                                continue;
@@ -1160,24 +1237,19 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                switch (event) {
                case SND_SOC_DAPM_STREAM_START:
                case SND_SOC_DAPM_STREAM_RESUME:
-                       dapm->dev_power = 1;
+                       dapm->target_bias_level = SND_SOC_BIAS_ON;
                        break;
                case SND_SOC_DAPM_STREAM_STOP:
-                       dapm->dev_power = !!dapm->codec->active;
+                       if (dapm->codec->active)
+                               dapm->target_bias_level = SND_SOC_BIAS_ON;
+                       else
+                               dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
                        break;
                case SND_SOC_DAPM_STREAM_SUSPEND:
-                       dapm->dev_power = 0;
+                       dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
                        break;
                case SND_SOC_DAPM_STREAM_NOP:
-                       switch (dapm->bias_level) {
-                               case SND_SOC_BIAS_STANDBY:
-                               case SND_SOC_BIAS_OFF:
-                                       dapm->dev_power = 0;
-                                       break;
-                               default:
-                                       dapm->dev_power = 1;
-                                       break;
-                       }
+                       dapm->target_bias_level = dapm->bias_level;
                        break;
                default:
                        break;
@@ -1185,12 +1257,12 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
        }
 
        /* Force all contexts in the card to the same bias state */
-       power = 0;
+       bias = SND_SOC_BIAS_OFF;
        list_for_each_entry(d, &card->dapm_list, list)
-               if (d->dev_power)
-                       power = 1;
+               if (d->target_bias_level > bias)
+                       bias = d->target_bias_level;
        list_for_each_entry(d, &card->dapm_list, list)
-               d->dev_power = power;
+               d->target_bias_level = bias;
 
 
        /* Run all the bias changes in parallel */
@@ -1794,6 +1866,84 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
 
+static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
+                                  const struct snd_soc_dapm_route *route)
+{
+       struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
+                                                             route->source,
+                                                             true);
+       struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
+                                                           route->sink,
+                                                           true);
+       struct snd_soc_dapm_path *path;
+       int count = 0;
+
+       if (!source) {
+               dev_err(dapm->dev, "Unable to find source %s for weak route\n",
+                       route->source);
+               return -ENODEV;
+       }
+
+       if (!sink) {
+               dev_err(dapm->dev, "Unable to find sink %s for weak route\n",
+                       route->sink);
+               return -ENODEV;
+       }
+
+       if (route->control || route->connected)
+               dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n",
+                        route->source, route->sink);
+
+       list_for_each_entry(path, &source->sinks, list_source) {
+               if (path->sink == sink) {
+                       path->weak = 1;
+                       count++;
+               }
+       }
+
+       if (count == 0)
+               dev_err(dapm->dev, "No path found for weak route %s->%s\n",
+                       route->source, route->sink);
+       if (count > 1)
+               dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n",
+                        count, route->source, route->sink);
+
+       return 0;
+}
+
+/**
+ * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
+ * @dapm: DAPM context
+ * @route: audio routes
+ * @num: number of routes
+ *
+ * Mark existing routes matching those specified in the passed array
+ * as being weak, meaning that they are ignored for the purpose of
+ * power decisions.  The main intended use case is for sidetone paths
+ * which couple audio between other independent paths if they are both
+ * active in order to make the combination work better at the user
+ * level but which aren't intended to be "used".
+ *
+ * Note that CODEC drivers should not use this as sidetone type paths
+ * can frequently also be used as bypass paths.
+ */
+int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
+                            const struct snd_soc_dapm_route *route, int num)
+{
+       int i, err;
+       int ret = 0;
+
+       for (i = 0; i < num; i++) {
+               err = snd_soc_dapm_weak_route(dapm, route);
+               if (err)
+                       ret = err;
+               route++;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
+
 /**
  * snd_soc_dapm_new_widgets - add new dapm widgets
  * @dapm: DAPM context
@@ -1865,7 +2015,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 
                /* Read the initial power state from the device */
                if (w->reg >= 0) {
-                       val = snd_soc_read(w->codec, w->reg);
+                       val = soc_widget_read(w, w->reg);
                        val &= 1 << w->shift;
                        if (w->invert)
                                val = !val;
@@ -2353,6 +2503,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        dapm->n_widgets++;
        w->dapm = dapm;
        w->codec = dapm->codec;
+       w->platform = dapm->platform;
        INIT_LIST_HEAD(&w->sources);
        INIT_LIST_HEAD(&w->sinks);
        INIT_LIST_HEAD(&w->list);
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
new file mode 100644 (file)
index 0000000..cca490c
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * soc-io.c  --  ASoC register I/O helpers
+ *
+ * Copyright 2009-2011 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include <trace/events/asoc.h>
+
+#ifdef CONFIG_SPI_MASTER
+static int do_spi_write(void *control, const char *data, int len)
+{
+       struct spi_device *spi = control;
+       int ret;
+
+       ret = spi_write(spi, data, len);
+       if (ret < 0)
+               return ret;
+
+       return len;
+}
+#endif
+
+static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+                      unsigned int value, const void *data, int len)
+{
+       int ret;
+
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+           reg < codec->driver->reg_cache_size &&
+           !codec->cache_bypass) {
+               ret = snd_soc_cache_write(codec, reg, value);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (codec->cache_only) {
+               codec->cache_sync = 1;
+               return 0;
+       }
+
+       ret = codec->hw_write(codec->control_data, data, len);
+       if (ret == len)
+               return 0;
+       if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       int ret;
+       unsigned int val;
+
+       if (reg >= codec->driver->reg_cache_size ||
+           snd_soc_codec_volatile_register(codec, reg) ||
+           codec->cache_bypass) {
+               if (codec->cache_only)
+                       return -1;
+
+               BUG_ON(!codec->hw_read);
+               return codec->hw_read(codec, reg);
+       }
+
+       ret = snd_soc_cache_read(codec, reg, &val);
+       if (ret < 0)
+               return -1;
+       return val;
+}
+
+static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
+                             unsigned int value)
+{
+       u16 data;
+
+       data = cpu_to_be16((reg << 12) | (value & 0xffffff));
+
+       return do_hw_write(codec, reg, value, &data, 2);
+}
+
+static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int value)
+{
+       u16 data;
+
+       data = cpu_to_be16((reg << 9) | (value & 0x1ff));
+
+       return do_hw_write(codec, reg, value, &data, 2);
+}
+
+static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int value)
+{
+       u8 data[2];
+
+       reg &= 0xff;
+       data[0] = reg;
+       data[1] = value & 0xff;
+
+       return do_hw_write(codec, reg, value, data, 2);
+}
+
+static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
+                             unsigned int value)
+{
+       u8 data[3];
+       u16 val = cpu_to_be16(value);
+
+       data[0] = reg;
+       memcpy(&data[1], &val, sizeof(val));
+
+       return do_hw_write(codec, reg, value, data, 3);
+}
+
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int do_i2c_read(struct snd_soc_codec *codec,
+                               void *reg, int reglen,
+                               void *data, int datalen)
+{
+       struct i2c_msg xfer[2];
+       int ret;
+       struct i2c_client *client = codec->control_data;
+
+       /* Write register */
+       xfer[0].addr = client->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = reglen;
+       xfer[0].buf = reg;
+
+       /* Read data */
+       xfer[1].addr = client->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = datalen;
+       xfer[1].buf = data;
+
+       ret = i2c_transfer(client->adapter, xfer, 2);
+       if (ret == 2)
+               return 0;
+       else if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+#endif
+
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
+                                        unsigned int r)
+{
+       u8 reg = r;
+       u8 data;
+       int ret;
+
+       ret = do_i2c_read(codec, &reg, 1, &data, 1);
+       if (ret < 0)
+               return 0;
+       return data;
+}
+#else
+#define snd_soc_8_8_read_i2c NULL
+#endif
+
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
+                                         unsigned int r)
+{
+       u8 reg = r;
+       u16 data;
+       int ret;
+
+       ret = do_i2c_read(codec, &reg, 1, &data, 2);
+       if (ret < 0)
+               return 0;
+       return (data >> 8) | ((data & 0xff) << 8);
+}
+#else
+#define snd_soc_8_16_read_i2c NULL
+#endif
+
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
+                                         unsigned int r)
+{
+       u16 reg = r;
+       u8 data;
+       int ret;
+
+       ret = do_i2c_read(codec, &reg, 2, &data, 1);
+       if (ret < 0)
+               return 0;
+       return data;
+}
+#else
+#define snd_soc_16_8_read_i2c NULL
+#endif
+
+static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
+                             unsigned int value)
+{
+       u8 data[3];
+       u16 rval = cpu_to_be16(reg);
+
+       memcpy(data, &rval, sizeof(rval));
+       data[2] = value;
+
+       return do_hw_write(codec, reg, value, data, 3);
+}
+
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
+                                          unsigned int r)
+{
+       u16 reg = cpu_to_be16(r);
+       u16 data;
+       int ret;
+
+       ret = do_i2c_read(codec, &reg, 2, &data, 2);
+       if (ret < 0)
+               return 0;
+       return be16_to_cpu(data);
+}
+#else
+#define snd_soc_16_16_read_i2c NULL
+#endif
+
+static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
+                              unsigned int value)
+{
+       u16 data[2];
+
+       data[0] = cpu_to_be16(reg);
+       data[1] = cpu_to_be16(value);
+
+       return do_hw_write(codec, reg, value, data, sizeof(data));
+}
+
+/* Primitive bulk write support for soc-cache.  The data pointed to by
+ * `data' needs to already be in the form the hardware expects
+ * including any leading register specific data.  Any data written
+ * through this function will not go through the cache as it only
+ * handles writing to volatile or out of bounds registers.
+ */
+static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
+                                    const void *data, size_t len)
+{
+       int ret;
+
+       /* To ensure that we don't get out of sync with the cache, check
+        * whether the base register is volatile or if we've directly asked
+        * to bypass the cache.  Out of bounds registers are considered
+        * volatile.
+        */
+       if (!codec->cache_bypass
+           && !snd_soc_codec_volatile_register(codec, reg)
+           && reg < codec->driver->reg_cache_size)
+               return -EINVAL;
+
+       switch (codec->control_type) {
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+       case SND_SOC_I2C:
+               ret = i2c_master_send(to_i2c_client(codec->dev), data, len);
+               break;
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       case SND_SOC_SPI:
+               ret = spi_write(to_spi_device(codec->dev), data, len);
+               break;
+#endif
+       default:
+               BUG();
+       }
+
+       if (ret == len)
+               return 0;
+       if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+static struct {
+       int addr_bits;
+       int data_bits;
+       int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
+       unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+       unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
+} io_types[] = {
+       {
+               .addr_bits = 4, .data_bits = 12,
+               .write = snd_soc_4_12_write,
+       },
+       {
+               .addr_bits = 7, .data_bits = 9,
+               .write = snd_soc_7_9_write,
+       },
+       {
+               .addr_bits = 8, .data_bits = 8,
+               .write = snd_soc_8_8_write,
+               .i2c_read = snd_soc_8_8_read_i2c,
+       },
+       {
+               .addr_bits = 8, .data_bits = 16,
+               .write = snd_soc_8_16_write,
+               .i2c_read = snd_soc_8_16_read_i2c,
+       },
+       {
+               .addr_bits = 16, .data_bits = 8,
+               .write = snd_soc_16_8_write,
+               .i2c_read = snd_soc_16_8_read_i2c,
+       },
+       {
+               .addr_bits = 16, .data_bits = 16,
+               .write = snd_soc_16_16_write,
+               .i2c_read = snd_soc_16_16_read_i2c,
+       },
+};
+
+/**
+ * snd_soc_codec_set_cache_io: Set up standard I/O functions.
+ *
+ * @codec: CODEC to configure.
+ * @addr_bits: Number of bits of register address data.
+ * @data_bits: Number of bits of data per register.
+ * @control: Control bus used.
+ *
+ * Register formats are frequently shared between many I2C and SPI
+ * devices.  In order to promote code reuse the ASoC core provides
+ * some standard implementations of CODEC read and write operations
+ * which can be set up using this function.
+ *
+ * The caller is responsible for allocating and initialising the
+ * actual cache.
+ *
+ * Note that at present this code cannot be used by CODECs with
+ * volatile registers.
+ */
+int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
+                              int addr_bits, int data_bits,
+                              enum snd_soc_control_type control)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(io_types); i++)
+               if (io_types[i].addr_bits == addr_bits &&
+                   io_types[i].data_bits == data_bits)
+                       break;
+       if (i == ARRAY_SIZE(io_types)) {
+               printk(KERN_ERR
+                      "No I/O functions for %d bit address %d bit data\n",
+                      addr_bits, data_bits);
+               return -EINVAL;
+       }
+
+       codec->write = io_types[i].write;
+       codec->read = hw_read;
+       codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
+
+       switch (control) {
+       case SND_SOC_I2C:
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+               codec->hw_write = (hw_write_t)i2c_master_send;
+#endif
+               if (io_types[i].i2c_read)
+                       codec->hw_read = io_types[i].i2c_read;
+
+               codec->control_data = container_of(codec->dev,
+                                                  struct i2c_client,
+                                                  dev);
+               break;
+
+       case SND_SOC_SPI:
+#ifdef CONFIG_SPI_MASTER
+               codec->hw_write = do_spi_write;
+#endif
+
+               codec->control_data = container_of(codec->dev,
+                                                  struct spi_device,
+                                                  dev);
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
+
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
new file mode 100644 (file)
index 0000000..b575939
--- /dev/null
@@ -0,0 +1,639 @@
+/*
+ * soc-pcm.c  --  ALSA SoC PCM
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ * Copyright (C) 2010 Slimlogic Ltd.
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Authors: Liam Girdwood <lrg@ti.com>
+ *          Mark Brown <broonie@opensource.wolfsonmicro.com>       
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+static DEFINE_MUTEX(pcm_mutex);
+
+static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       if (!codec_dai->driver->symmetric_rates &&
+           !cpu_dai->driver->symmetric_rates &&
+           !rtd->dai_link->symmetric_rates)
+               return 0;
+
+       /* This can happen if multiple streams are starting simultaneously -
+        * the second can need to get its constraints before the first has
+        * picked a rate.  Complain and allow the application to carry on.
+        */
+       if (!rtd->rate) {
+               dev_warn(&rtd->dev,
+                        "Not enforcing symmetric_rates due to race\n");
+               return 0;
+       }
+
+       dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", rtd->rate);
+
+       ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                          SNDRV_PCM_HW_PARAM_RATE,
+                                          rtd->rate, rtd->rate);
+       if (ret < 0) {
+               dev_err(&rtd->dev,
+                       "Unable to apply rate symmetry constraint: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Called by ALSA when a PCM substream is opened, the runtime->hw record is
+ * then initialized and any private data can be allocated. This also calls
+ * startup for the cpu DAI, platform, machine and codec DAI.
+ */
+static int soc_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
+       struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
+       int ret = 0;
+
+       mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+
+       /* startup the audio subsystem */
+       if (cpu_dai->driver->ops->startup) {
+               ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: can't open interface %s\n",
+                               cpu_dai->name);
+                       goto out;
+               }
+       }
+
+       if (platform->driver->ops && platform->driver->ops->open) {
+               ret = platform->driver->ops->open(substream);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
+                       goto platform_err;
+               }
+       }
+
+       if (codec_dai->driver->ops->startup) {
+               ret = codec_dai->driver->ops->startup(substream, codec_dai);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: can't open codec %s\n",
+                               codec_dai->name);
+                       goto codec_dai_err;
+               }
+       }
+
+       if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
+               ret = rtd->dai_link->ops->startup(substream);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
+                       goto machine_err;
+               }
+       }
+
+       /* Check that the codec and cpu DAIs are compatible */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               runtime->hw.rate_min =
+                       max(codec_dai_drv->playback.rate_min,
+                           cpu_dai_drv->playback.rate_min);
+               runtime->hw.rate_max =
+                       min(codec_dai_drv->playback.rate_max,
+                           cpu_dai_drv->playback.rate_max);
+               runtime->hw.channels_min =
+                       max(codec_dai_drv->playback.channels_min,
+                               cpu_dai_drv->playback.channels_min);
+               runtime->hw.channels_max =
+                       min(codec_dai_drv->playback.channels_max,
+                               cpu_dai_drv->playback.channels_max);
+               runtime->hw.formats =
+                       codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
+               runtime->hw.rates =
+                       codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
+               if (codec_dai_drv->playback.rates
+                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
+                       runtime->hw.rates |= cpu_dai_drv->playback.rates;
+               if (cpu_dai_drv->playback.rates
+                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
+                       runtime->hw.rates |= codec_dai_drv->playback.rates;
+       } else {
+               runtime->hw.rate_min =
+                       max(codec_dai_drv->capture.rate_min,
+                           cpu_dai_drv->capture.rate_min);
+               runtime->hw.rate_max =
+                       min(codec_dai_drv->capture.rate_max,
+                           cpu_dai_drv->capture.rate_max);
+               runtime->hw.channels_min =
+                       max(codec_dai_drv->capture.channels_min,
+                               cpu_dai_drv->capture.channels_min);
+               runtime->hw.channels_max =
+                       min(codec_dai_drv->capture.channels_max,
+                               cpu_dai_drv->capture.channels_max);
+               runtime->hw.formats =
+                       codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
+               runtime->hw.rates =
+                       codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
+               if (codec_dai_drv->capture.rates
+                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
+                       runtime->hw.rates |= cpu_dai_drv->capture.rates;
+               if (cpu_dai_drv->capture.rates
+                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
+                       runtime->hw.rates |= codec_dai_drv->capture.rates;
+       }
+
+       ret = -EINVAL;
+       snd_pcm_limit_hw_rates(runtime);
+       if (!runtime->hw.rates) {
+               printk(KERN_ERR "asoc: %s <-> %s No matching rates\n",
+                       codec_dai->name, cpu_dai->name);
+               goto config_err;
+       }
+       if (!runtime->hw.formats) {
+               printk(KERN_ERR "asoc: %s <-> %s No matching formats\n",
+                       codec_dai->name, cpu_dai->name);
+               goto config_err;
+       }
+       if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
+           runtime->hw.channels_min > runtime->hw.channels_max) {
+               printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
+                               codec_dai->name, cpu_dai->name);
+               goto config_err;
+       }
+
+       /* Symmetry only applies if we've already got an active stream. */
+       if (cpu_dai->active || codec_dai->active) {
+               ret = soc_pcm_apply_symmetry(substream);
+               if (ret != 0)
+                       goto config_err;
+       }
+
+       pr_debug("asoc: %s <-> %s info:\n",
+                       codec_dai->name, cpu_dai->name);
+       pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
+       pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
+                runtime->hw.channels_max);
+       pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
+                runtime->hw.rate_max);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               cpu_dai->playback_active++;
+               codec_dai->playback_active++;
+       } else {
+               cpu_dai->capture_active++;
+               codec_dai->capture_active++;
+       }
+       cpu_dai->active++;
+       codec_dai->active++;
+       rtd->codec->active++;
+       mutex_unlock(&rtd->pcm_mutex);
+       return 0;
+
+config_err:
+       if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+               rtd->dai_link->ops->shutdown(substream);
+
+machine_err:
+       if (codec_dai->driver->ops->shutdown)
+               codec_dai->driver->ops->shutdown(substream, codec_dai);
+
+codec_dai_err:
+       if (platform->driver->ops && platform->driver->ops->close)
+               platform->driver->ops->close(substream);
+
+platform_err:
+       if (cpu_dai->driver->ops->shutdown)
+               cpu_dai->driver->ops->shutdown(substream, cpu_dai);
+out:
+       mutex_unlock(&rtd->pcm_mutex);
+       return ret;
+}
+
+/*
+ * Power down the audio subsystem pmdown_time msecs after close is called.
+ * This is to ensure there are no pops or clicks in between any music tracks
+ * due to DAPM power cycling.
+ */
+static void close_delayed_work(struct work_struct *work)
+{
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+
+       pr_debug("pop wq checking: %s status: %s waiting: %s\n",
+                codec_dai->driver->playback.stream_name,
+                codec_dai->playback_active ? "active" : "inactive",
+                codec_dai->pop_wait ? "yes" : "no");
+
+       /* are we waiting on this codec DAI stream */
+       if (codec_dai->pop_wait == 1) {
+               codec_dai->pop_wait = 0;
+               snd_soc_dapm_stream_event(rtd,
+                       codec_dai->driver->playback.stream_name,
+                       SND_SOC_DAPM_STREAM_STOP);
+       }
+
+       mutex_unlock(&rtd->pcm_mutex);
+}
+
+/*
+ * Called by ALSA when a PCM substream is closed. Private data can be
+ * freed here. The cpu DAI, codec DAI, machine and platform are also
+ * shutdown.
+ */
+static int soc_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+
+       mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               cpu_dai->playback_active--;
+               codec_dai->playback_active--;
+       } else {
+               cpu_dai->capture_active--;
+               codec_dai->capture_active--;
+       }
+
+       cpu_dai->active--;
+       codec_dai->active--;
+       codec->active--;
+
+       /* Muting the DAC suppresses artifacts caused during digital
+        * shutdown, for example from stopping clocks.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               snd_soc_dai_digital_mute(codec_dai, 1);
+
+       if (cpu_dai->driver->ops->shutdown)
+               cpu_dai->driver->ops->shutdown(substream, cpu_dai);
+
+       if (codec_dai->driver->ops->shutdown)
+               codec_dai->driver->ops->shutdown(substream, codec_dai);
+
+       if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+               rtd->dai_link->ops->shutdown(substream);
+
+       if (platform->driver->ops && platform->driver->ops->close)
+               platform->driver->ops->close(substream);
+       cpu_dai->runtime = NULL;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               /* start delayed pop wq here for playback streams */
+               codec_dai->pop_wait = 1;
+               schedule_delayed_work(&rtd->delayed_work,
+                       msecs_to_jiffies(rtd->pmdown_time));
+       } else {
+               /* capture streams can be powered down now */
+               snd_soc_dapm_stream_event(rtd,
+                       codec_dai->driver->capture.stream_name,
+                       SND_SOC_DAPM_STREAM_STOP);
+       }
+
+       mutex_unlock(&rtd->pcm_mutex);
+       return 0;
+}
+
+/*
+ * Called by ALSA when the PCM substream is prepared, can set format, sample
+ * rate, etc.  This function is non atomic and can be called multiple times,
+ * it can refer to the runtime info.
+ */
+static int soc_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret = 0;
+
+       mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+
+       if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
+               ret = rtd->dai_link->ops->prepare(substream);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: machine prepare error\n");
+                       goto out;
+               }
+       }
+
+       if (platform->driver->ops && platform->driver->ops->prepare) {
+               ret = platform->driver->ops->prepare(substream);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: platform prepare error\n");
+                       goto out;
+               }
+       }
+
+       if (codec_dai->driver->ops->prepare) {
+               ret = codec_dai->driver->ops->prepare(substream, codec_dai);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: codec DAI prepare error\n");
+                       goto out;
+               }
+       }
+
+       if (cpu_dai->driver->ops->prepare) {
+               ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: cpu DAI prepare error\n");
+                       goto out;
+               }
+       }
+
+       /* cancel any delayed stream shutdown that is pending */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+           codec_dai->pop_wait) {
+               codec_dai->pop_wait = 0;
+               cancel_delayed_work(&rtd->delayed_work);
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               snd_soc_dapm_stream_event(rtd,
+                                         codec_dai->driver->playback.stream_name,
+                                         SND_SOC_DAPM_STREAM_START);
+       else
+               snd_soc_dapm_stream_event(rtd,
+                                         codec_dai->driver->capture.stream_name,
+                                         SND_SOC_DAPM_STREAM_START);
+
+       snd_soc_dai_digital_mute(codec_dai, 0);
+
+out:
+       mutex_unlock(&rtd->pcm_mutex);
+       return ret;
+}
+
+/*
+ * Called by ALSA when the hardware params are set by application. This
+ * function can also be called multiple times and can allocate buffers
+ * (using snd_pcm_lib_* ). It's non-atomic.
+ */
+static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret = 0;
+
+       mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+
+       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
+               ret = rtd->dai_link->ops->hw_params(substream, params);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: machine hw_params failed\n");
+                       goto out;
+               }
+       }
+
+       if (codec_dai->driver->ops->hw_params) {
+               ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: can't set codec %s hw params\n",
+                               codec_dai->name);
+                       goto codec_err;
+               }
+       }
+
+       if (cpu_dai->driver->ops->hw_params) {
+               ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: interface %s hw params failed\n",
+                               cpu_dai->name);
+                       goto interface_err;
+               }
+       }
+
+       if (platform->driver->ops && platform->driver->ops->hw_params) {
+               ret = platform->driver->ops->hw_params(substream, params);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: platform %s hw params failed\n",
+                               platform->name);
+                       goto platform_err;
+               }
+       }
+
+       rtd->rate = params_rate(params);
+
+out:
+       mutex_unlock(&rtd->pcm_mutex);
+       return ret;
+
+platform_err:
+       if (cpu_dai->driver->ops->hw_free)
+               cpu_dai->driver->ops->hw_free(substream, cpu_dai);
+
+interface_err:
+       if (codec_dai->driver->ops->hw_free)
+               codec_dai->driver->ops->hw_free(substream, codec_dai);
+
+codec_err:
+       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+               rtd->dai_link->ops->hw_free(substream);
+
+       mutex_unlock(&rtd->pcm_mutex);
+       return ret;
+}
+
+/*
+ * Frees resources allocated by hw_params, can be called multiple times
+ */
+static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+
+       mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+
+       /* apply codec digital mute */
+       if (!codec->active)
+               snd_soc_dai_digital_mute(codec_dai, 1);
+
+       /* free any machine hw params */
+       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+               rtd->dai_link->ops->hw_free(substream);
+
+       /* free any DMA resources */
+       if (platform->driver->ops && platform->driver->ops->hw_free)
+               platform->driver->ops->hw_free(substream);
+
+       /* now free hw params for the DAIs  */
+       if (codec_dai->driver->ops->hw_free)
+               codec_dai->driver->ops->hw_free(substream, codec_dai);
+
+       if (cpu_dai->driver->ops->hw_free)
+               cpu_dai->driver->ops->hw_free(substream, cpu_dai);
+
+       mutex_unlock(&rtd->pcm_mutex);
+       return 0;
+}
+
+static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       if (codec_dai->driver->ops->trigger) {
+               ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (platform->driver->ops && platform->driver->ops->trigger) {
+               ret = platform->driver->ops->trigger(substream, cmd);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (cpu_dai->driver->ops->trigger) {
+               ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+/*
+ * soc level wrapper for pointer callback
+ * If cpu_dai, codec_dai, platform driver has the delay callback, than
+ * the runtime->delay will be updated accordingly.
+ */
+static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       snd_pcm_uframes_t offset = 0;
+       snd_pcm_sframes_t delay = 0;
+
+       if (platform->driver->ops && platform->driver->ops->pointer)
+               offset = platform->driver->ops->pointer(substream);
+
+       if (cpu_dai->driver->ops->delay)
+               delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
+
+       if (codec_dai->driver->ops->delay)
+               delay += codec_dai->driver->ops->delay(substream, codec_dai);
+
+       if (platform->driver->delay)
+               delay += platform->driver->delay(substream, codec_dai);
+
+       runtime->delay = delay;
+
+       return offset;
+}
+
+/* ASoC PCM operations */
+static struct snd_pcm_ops soc_pcm_ops = {
+       .open           = soc_pcm_open,
+       .close          = soc_pcm_close,
+       .hw_params      = soc_pcm_hw_params,
+       .hw_free        = soc_pcm_hw_free,
+       .prepare        = soc_pcm_prepare,
+       .trigger        = soc_pcm_trigger,
+       .pointer        = soc_pcm_pointer,
+};
+
+/* create a new pcm */
+int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_pcm *pcm;
+       char new_name[64];
+       int ret = 0, playback = 0, capture = 0;
+
+       /* check client and interface hw capabilities */
+       snprintf(new_name, sizeof(new_name), "%s %s-%d",
+                       rtd->dai_link->stream_name, codec_dai->name, num);
+
+       if (codec_dai->driver->playback.channels_min)
+               playback = 1;
+       if (codec_dai->driver->capture.channels_min)
+               capture = 1;
+
+       dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
+       ret = snd_pcm_new(rtd->card->snd_card, new_name,
+                       num, playback, capture, &pcm);
+       if (ret < 0) {
+               printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
+               return ret;
+       }
+
+       /* DAPM dai link stream work */
+       INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+
+       rtd->pcm = pcm;
+       pcm->private_data = rtd;
+       if (platform->driver->ops) {
+               soc_pcm_ops.mmap = platform->driver->ops->mmap;
+               soc_pcm_ops.pointer = platform->driver->ops->pointer;
+               soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
+               soc_pcm_ops.copy = platform->driver->ops->copy;
+               soc_pcm_ops.silence = platform->driver->ops->silence;
+               soc_pcm_ops.ack = platform->driver->ops->ack;
+               soc_pcm_ops.page = platform->driver->ops->page;
+       }
+
+       if (playback)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
+
+       if (capture)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
+
+       if (platform->driver->pcm_new) {
+               ret = platform->driver->pcm_new(rtd);
+               if (ret < 0) {
+                       pr_err("asoc: platform pcm constructor failed\n");
+                       return ret;
+               }
+       }
+
+       pcm->private_free = platform->driver->pcm_free;
+       printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
+               cpu_dai->name);
+       return ret;
+}
index 035d39a..c6af1fd 100644 (file)
@@ -12,6 +12,15 @@ config SND_SOC_TEGRA_I2S
          Tegra I2S interface. You will also need to select the individual
          machine drivers to support below.
 
+config SND_SOC_TEGRA_SPDIF
+       tristate
+       depends on SND_SOC_TEGRA
+       default m
+       help
+         Say Y or M if you want to add support for the SPDIF interface.
+         You will also need to select the individual machine drivers to support
+         below.
+
 config MACH_HAS_SND_SOC_TEGRA_WM8903
        bool
        help
index fa6574d..4d943b3 100644 (file)
@@ -2,12 +2,14 @@
 snd-soc-tegra-das-objs := tegra_das.o
 snd-soc-tegra-pcm-objs := tegra_pcm.o
 snd-soc-tegra-i2s-objs := tegra_i2s.o
+snd-soc-tegra-spdif-objs := tegra_spdif.o
 snd-soc-tegra-utils-objs += tegra_asoc_utils.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA_SPDIF) += snd-soc-tegra-spdif.o
 
 # Tegra machine Support
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
index 95f03c1..f36b996 100644 (file)
@@ -354,7 +354,6 @@ struct snd_soc_dai_driver tegra_i2s_dai[] = {
 static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
 {
        struct tegra_i2s * i2s;
-       char clk_name[12]; /* tegra-i2s.0 */
        struct resource *mem, *memregion, *dmareq;
        int ret;
 
@@ -389,8 +388,7 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
        }
        dev_set_drvdata(&pdev->dev, i2s);
 
-       snprintf(clk_name, sizeof(clk_name), DRV_NAME ".%d", pdev->id);
-       i2s->clk_i2s = clk_get_sys(clk_name, NULL);
+       i2s->clk_i2s = clk_get(&pdev->dev, NULL);
        if (IS_ERR(i2s->clk_i2s)) {
                dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
                ret = PTR_ERR(i2s->clk_i2s);
index 3c271f9..ff86e5e 100644 (file)
@@ -322,9 +322,11 @@ static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 
 static u64 tegra_dma_mask = DMA_BIT_MASK(32);
 
-static int tegra_pcm_new(struct snd_card *card,
-                               struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        if (!card->dev->dma_mask)
diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c
new file mode 100644 (file)
index 0000000..abe606b
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * tegra_spdif.c - Tegra SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <mach/iomap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra_spdif.h"
+
+#define DRV_NAME "tegra-spdif"
+
+static inline void tegra_spdif_write(struct tegra_spdif *spdif, u32 reg,
+                                       u32 val)
+{
+       __raw_writel(val, spdif->regs + reg);
+}
+
+static inline u32 tegra_spdif_read(struct tegra_spdif *spdif, u32 reg)
+{
+       return __raw_readl(spdif->regs + reg);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int tegra_spdif_show(struct seq_file *s, void *unused)
+{
+#define REG(r) { r, #r }
+       static const struct {
+               int offset;
+               const char *name;
+       } regs[] = {
+               REG(TEGRA_SPDIF_CTRL),
+               REG(TEGRA_SPDIF_STATUS),
+               REG(TEGRA_SPDIF_STROBE_CTRL),
+               REG(TEGRA_SPDIF_DATA_FIFO_CSR),
+               REG(TEGRA_SPDIF_CH_STA_RX_A),
+               REG(TEGRA_SPDIF_CH_STA_RX_B),
+               REG(TEGRA_SPDIF_CH_STA_RX_C),
+               REG(TEGRA_SPDIF_CH_STA_RX_D),
+               REG(TEGRA_SPDIF_CH_STA_RX_E),
+               REG(TEGRA_SPDIF_CH_STA_RX_F),
+               REG(TEGRA_SPDIF_CH_STA_TX_A),
+               REG(TEGRA_SPDIF_CH_STA_TX_B),
+               REG(TEGRA_SPDIF_CH_STA_TX_C),
+               REG(TEGRA_SPDIF_CH_STA_TX_D),
+               REG(TEGRA_SPDIF_CH_STA_TX_E),
+               REG(TEGRA_SPDIF_CH_STA_TX_F),
+       };
+#undef REG
+
+       struct tegra_spdif *spdif = s->private;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(regs); i++) {
+               u32 val = tegra_spdif_read(spdif, regs[i].offset);
+               seq_printf(s, "%s = %08x\n", regs[i].name, val);
+       }
+
+       return 0;
+}
+
+static int tegra_spdif_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, tegra_spdif_show, inode->i_private);
+}
+
+static const struct file_operations tegra_spdif_debug_fops = {
+       .open    = tegra_spdif_debug_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = single_release,
+};
+
+static void tegra_spdif_debug_add(struct tegra_spdif *spdif)
+{
+       spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
+                                               snd_soc_debugfs_root, spdif,
+                                               &tegra_spdif_debug_fops);
+}
+
+static void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
+{
+       if (spdif->debug)
+               debugfs_remove(spdif->debug);
+}
+#else
+static inline void tegra_spdif_debug_add(struct tegra_spdif *spdif)
+{
+}
+
+static inline void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
+{
+}
+#endif
+
+static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct device *dev = substream->pcm->card->dev;
+       struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+       int ret, srate, spdifclock;
+
+       spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_PACK;
+       spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_BIT_MODE_MASK;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_PACK;
+               spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_BIT_MODE_16BIT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       srate = params_rate(params);
+       switch (params_rate(params)) {
+       case 32000:
+               spdifclock = 4096000;
+               break;
+       case 44100:
+               spdifclock = 5644800;
+               break;
+       case 48000:
+               spdifclock = 6144000;
+               break;
+       case 88200:
+               spdifclock = 11289600;
+               break;
+       case 96000:
+               spdifclock = 12288000;
+               break;
+       case 176400:
+               spdifclock = 22579200;
+               break;
+       case 192000:
+               spdifclock = 24576000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
+       if (ret) {
+               dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void tegra_spdif_start_playback(struct tegra_spdif *spdif)
+{
+       spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_TX_EN;
+       tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static void tegra_spdif_stop_playback(struct tegra_spdif *spdif)
+{
+       spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_TX_EN;
+       tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static int tegra_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (!spdif->clk_refs)
+                       clk_enable(spdif->clk_spdif_out);
+               spdif->clk_refs++;
+               tegra_spdif_start_playback(spdif);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               tegra_spdif_stop_playback(spdif);
+               spdif->clk_refs--;
+               if (!spdif->clk_refs)
+                       clk_disable(spdif->clk_spdif_out);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tegra_spdif_probe(struct snd_soc_dai *dai)
+{
+       struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+       dai->capture_dma_data = NULL;
+       dai->playback_dma_data = &spdif->playback_dma_data;
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops tegra_spdif_dai_ops = {
+       .hw_params      = tegra_spdif_hw_params,
+       .trigger        = tegra_spdif_trigger,
+};
+
+struct snd_soc_dai_driver tegra_spdif_dai = {
+       .name = DRV_NAME,
+       .probe = tegra_spdif_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+                               SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &tegra_spdif_dai_ops,
+};
+
+static __devinit int tegra_spdif_platform_probe(struct platform_device *pdev)
+{
+       struct tegra_spdif *spdif;
+       struct resource *mem, *memregion, *dmareq;
+       int ret;
+
+       spdif = kzalloc(sizeof(struct tegra_spdif), GFP_KERNEL);
+       if (!spdif) {
+               dev_err(&pdev->dev, "Can't allocate tegra_spdif\n");
+               ret = -ENOMEM;
+               goto exit;
+       }
+       dev_set_drvdata(&pdev->dev, spdif);
+
+       spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
+       if (IS_ERR(spdif->clk_spdif_out)) {
+               pr_err("Can't retrieve spdif clock\n");
+               ret = PTR_ERR(spdif->clk_spdif_out);
+               goto err_free;
+       }
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "No memory resource\n");
+               ret = -ENODEV;
+               goto err_clk_put;
+       }
+
+       dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dmareq) {
+               dev_err(&pdev->dev, "No DMA resource\n");
+               ret = -ENODEV;
+               goto err_clk_put;
+       }
+
+       memregion = request_mem_region(mem->start, resource_size(mem),
+                                       DRV_NAME);
+       if (!memregion) {
+               dev_err(&pdev->dev, "Memory region already claimed\n");
+               ret = -EBUSY;
+               goto err_clk_put;
+       }
+
+       spdif->regs = ioremap(mem->start, resource_size(mem));
+       if (!spdif->regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto err_release;
+       }
+
+       spdif->playback_dma_data.addr = mem->start + TEGRA_SPDIF_DATA_OUT;
+       spdif->playback_dma_data.wrap = 4;
+       spdif->playback_dma_data.width = 32;
+       spdif->playback_dma_data.req_sel = dmareq->start;
+
+       ret = snd_soc_register_dai(&pdev->dev, &tegra_spdif_dai);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+               ret = -ENOMEM;
+               goto err_unmap;
+       }
+
+       tegra_spdif_debug_add(spdif);
+
+       return 0;
+
+err_unmap:
+       iounmap(spdif->regs);
+err_release:
+       release_mem_region(mem->start, resource_size(mem));
+err_clk_put:
+       clk_put(spdif->clk_spdif_out);
+err_free:
+       kfree(spdif);
+exit:
+       return ret;
+}
+
+static int __devexit tegra_spdif_platform_remove(struct platform_device *pdev)
+{
+       struct tegra_spdif *spdif = dev_get_drvdata(&pdev->dev);
+       struct resource *res;
+
+       snd_soc_unregister_dai(&pdev->dev);
+
+       tegra_spdif_debug_remove(spdif);
+
+       iounmap(spdif->regs);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+
+       clk_put(spdif->clk_spdif_out);
+
+       kfree(spdif);
+
+       return 0;
+}
+
+static struct platform_driver tegra_spdif_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = tegra_spdif_platform_probe,
+       .remove = __devexit_p(tegra_spdif_platform_remove),
+};
+
+static int __init snd_tegra_spdif_init(void)
+{
+       return platform_driver_register(&tegra_spdif_driver);
+}
+module_init(snd_tegra_spdif_init);
+
+static void __exit snd_tegra_spdif_exit(void)
+{
+       platform_driver_unregister(&tegra_spdif_driver);
+}
+module_exit(snd_tegra_spdif_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra SPDIF ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_spdif.h b/sound/soc/tegra/tegra_spdif.h
new file mode 100644 (file)
index 0000000..2e03db4
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * tegra_spdif.h - Definitions for Tegra SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ * Copyright (c) 2008-2009, NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA_SPDIF_H__
+#define __TEGRA_SPDIF_H__
+
+#include "tegra_pcm.h"
+
+/* Offsets from TEGRA_SPDIF_BASE */
+
+#define TEGRA_SPDIF_CTRL                                       0x0
+#define TEGRA_SPDIF_STATUS                                     0x4
+#define TEGRA_SPDIF_STROBE_CTRL                                        0x8
+#define TEGRA_SPDIF_DATA_FIFO_CSR                              0x0C
+#define TEGRA_SPDIF_DATA_OUT                                   0x40
+#define TEGRA_SPDIF_DATA_IN                                    0x80
+#define TEGRA_SPDIF_CH_STA_RX_A                                        0x100
+#define TEGRA_SPDIF_CH_STA_RX_B                                        0x104
+#define TEGRA_SPDIF_CH_STA_RX_C                                        0x108
+#define TEGRA_SPDIF_CH_STA_RX_D                                        0x10C
+#define TEGRA_SPDIF_CH_STA_RX_E                                        0x110
+#define TEGRA_SPDIF_CH_STA_RX_F                                        0x114
+#define TEGRA_SPDIF_CH_STA_TX_A                                        0x140
+#define TEGRA_SPDIF_CH_STA_TX_B                                        0x144
+#define TEGRA_SPDIF_CH_STA_TX_C                                        0x148
+#define TEGRA_SPDIF_CH_STA_TX_D                                        0x14C
+#define TEGRA_SPDIF_CH_STA_TX_E                                        0x150
+#define TEGRA_SPDIF_CH_STA_TX_F                                        0x154
+#define TEGRA_SPDIF_USR_STA_RX_A                               0x180
+#define TEGRA_SPDIF_USR_DAT_TX_A                               0x1C0
+
+/* Fields in TEGRA_SPDIF_CTRL */
+
+/* Start capturing from 0=right, 1=left channel */
+#define TEGRA_SPDIF_CTRL_CAP_LC                                        (1 << 30)
+
+/* SPDIF receiver(RX) enable */
+#define TEGRA_SPDIF_CTRL_RX_EN                                 (1 << 29)
+
+/* SPDIF Transmitter(TX) enable */
+#define TEGRA_SPDIF_CTRL_TX_EN                                 (1 << 28)
+
+/* Transmit Channel status */
+#define TEGRA_SPDIF_CTRL_TC_EN                                 (1 << 27)
+
+/* Transmit user Data */
+#define TEGRA_SPDIF_CTRL_TU_EN                                 (1 << 26)
+
+/* Interrupt on transmit error */
+#define TEGRA_SPDIF_CTRL_IE_TXE                                        (1 << 25)
+
+/* Interrupt on receive error */
+#define TEGRA_SPDIF_CTRL_IE_RXE                                        (1 << 24)
+
+/* Interrupt on invalid preamble */
+#define TEGRA_SPDIF_CTRL_IE_P                                  (1 << 23)
+
+/* Interrupt on "B" preamble */
+#define TEGRA_SPDIF_CTRL_IE_B                                  (1 << 22)
+
+/* Interrupt when block of channel status received */
+#define TEGRA_SPDIF_CTRL_IE_C                                  (1 << 21)
+
+/* Interrupt when a valid information unit (IU) is received */
+#define TEGRA_SPDIF_CTRL_IE_U                                  (1 << 20)
+
+/* Interrupt when RX user FIFO attention level is reached */
+#define TEGRA_SPDIF_CTRL_QE_RU                                 (1 << 19)
+
+/* Interrupt when TX user FIFO attention level is reached */
+#define TEGRA_SPDIF_CTRL_QE_TU                                 (1 << 18)
+
+/* Interrupt when RX data FIFO attention level is reached */
+#define TEGRA_SPDIF_CTRL_QE_RX                                 (1 << 17)
+
+/* Interrupt when TX data FIFO attention level is reached */
+#define TEGRA_SPDIF_CTRL_QE_TX                                 (1 << 16)
+
+/* Loopback test mode enable */
+#define TEGRA_SPDIF_CTRL_LBK_EN                                        (1 << 15)
+
+/*
+ * Pack data mode:
+ * 0 = Single data (16 bit needs to be  padded to match the
+ *     interface data bit size).
+ * 1 = Packeted left/right channel data into a single word.
+ */
+#define TEGRA_SPDIF_CTRL_PACK                                  (1 << 14)
+
+/*
+ * 00 = 16bit data
+ * 01 = 20bit data
+ * 10 = 24bit data
+ * 11 = raw data
+ */
+#define TEGRA_SPDIF_BIT_MODE_16BIT                             0
+#define TEGRA_SPDIF_BIT_MODE_20BIT                             1
+#define TEGRA_SPDIF_BIT_MODE_24BIT                             2
+#define TEGRA_SPDIF_BIT_MODE_RAW                               3
+
+#define TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT                                12
+#define TEGRA_SPDIF_CTRL_BIT_MODE_MASK                         (3                          << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA_SPDIF_CTRL_BIT_MODE_16BIT                                (TEGRA_SPDIF_BIT_MODE_16BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA_SPDIF_CTRL_BIT_MODE_20BIT                                (TEGRA_SPDIF_BIT_MODE_20BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA_SPDIF_CTRL_BIT_MODE_24BIT                                (TEGRA_SPDIF_BIT_MODE_24BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA_SPDIF_CTRL_BIT_MODE_RAW                          (TEGRA_SPDIF_BIT_MODE_RAW   << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
+
+/* Fields in TEGRA_SPDIF_STATUS */
+
+/*
+ * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
+ * write a 1 to the corresponding bit location to clear the status.
+ */
+
+/*
+ * Receiver(RX) shifter is busy receiving data.
+ * This bit is asserted when the receiver first locked onto the
+ * preamble of the data stream after RX_EN is asserted. This bit is
+ * deasserted when either,
+ * (a) the end of a frame is reached after RX_EN is deeasserted, or
+ * (b) the SPDIF data stream becomes inactive.
+ */
+#define TEGRA_SPDIF_STATUS_RX_BSY                              (1 << 29)
+
+/*
+ * Transmitter(TX) shifter is busy transmitting data.
+ * This bit is asserted when TX_EN is asserted.
+ * This bit is deasserted when the end of a frame is reached after
+ * TX_EN is deasserted.
+ */
+#define TEGRA_SPDIF_STATUS_TX_BSY                              (1 << 28)
+
+/*
+ * TX is busy shifting out channel status.
+ * This bit is asserted when both TX_EN and TC_EN are asserted and
+ * data from CH_STA_TX_A register is loaded into the internal shifter.
+ * This bit is deasserted when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) CH_STA_TX_F register is loaded into the internal shifter.
+ */
+#define TEGRA_SPDIF_STATUS_TC_BSY                              (1 << 27)
+
+/*
+ * TX User data FIFO busy.
+ * This bit is asserted when TX_EN and TXU_EN are asserted and
+ * there's data in the TX user FIFO.  This bit is deassert when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) there's no data left in the TX user FIFO.
+ */
+#define TEGRA_SPDIF_STATUS_TU_BSY                              (1 << 26)
+
+/* TX FIFO Underrun error status */
+#define TEGRA_SPDIF_STATUS_TX_ERR                              (1 << 25)
+
+/* RX FIFO Overrun error status */
+#define TEGRA_SPDIF_STATUS_RX_ERR                              (1 << 24)
+
+/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
+#define TEGRA_SPDIF_STATUS_IS_P                                        (1 << 23)
+
+/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
+#define TEGRA_SPDIF_STATUS_IS_B                                        (1 << 22)
+
+/*
+ * RX channel block data receive status:
+ * 0=entire block not recieved yet.
+ * 1=received entire block of channel status,
+ */
+#define TEGRA_SPDIF_STATUS_IS_C                                        (1 << 21)
+
+/* RX User Data Valid flag:  1=valid IU detected, 0 = no IU detected. */
+#define TEGRA_SPDIF_STATUS_IS_U                                        (1 << 20)
+
+/*
+ * RX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA_SPDIF_STATUS_QS_RU                               (1 << 19)
+
+/*
+ * TX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA_SPDIF_STATUS_QS_TU                               (1 << 18)
+
+/*
+ * RX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA_SPDIF_STATUS_QS_RX                               (1 << 17)
+
+/*
+ * TX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA_SPDIF_STATUS_QS_TX                               (1 << 16)
+
+/* Fields in TEGRA_SPDIF_STROBE_CTRL */
+
+/*
+ * Indicates the approximate number of detected SPDIFIN clocks within a
+ * bi-phase period.
+ */
+#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT                   16
+#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_MASK                    (0xff << TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
+
+/* Data strobe mode: 0=Auto-locked 1=Manual locked */
+#define TEGRA_SPDIF_STROBE_CTRL_STROBE                         (1 << 15)
+
+/*
+ * Manual data strobe time within the bi-phase clock period (in terms of
+ * the number of over-sampling clocks).
+ */
+#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT             8
+#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_MASK              (0x1f << TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
+
+/*
+ * Manual SPDIFIN bi-phase clock period (in terms of the number of
+ * over-sampling clocks).
+ */
+#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT             0
+#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK              (0x3f << TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
+
+/* Fields in SPDIF_DATA_FIFO_CSR */
+
+/* Clear Receiver User FIFO (RX USR.FIFO) */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_CLR                       (1 << 31)
+
+#define TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT                    0
+#define TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS                   1
+#define TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS                 2
+#define TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS                  3
+
+/* RU FIFO attention level */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT             29
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK              \
+               (0x3                                    << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+
+/* Number of RX USR.FIFO levels with valid data. */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT          24
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK           (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter User FIFO (TX USR.FIFO) */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_CLR                       (1 << 23)
+
+/* TU FIFO attention level */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT             21
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK              \
+               (0x3                                   << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+
+/* Number of TX USR.FIFO levels that could be filled. */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT         16
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK          (0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
+
+/* Clear Receiver Data FIFO (RX DATA.FIFO) */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_CLR                       (1 << 15)
+
+#define TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT                    0
+#define TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS                  1
+#define TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS                 2
+#define TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS                        3
+
+/* RU FIFO attention level */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT             13
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK              \
+               (0x3                                     << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL    \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+
+/* Number of RX DATA.FIFO levels with valid data. */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT          8
+#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK           (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_CLR                       (1 << 7)
+
+/* TU FIFO attention level */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT             5
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK              \
+               (0x3                                     << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL     \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL    \
+               (TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+
+/* Number of TX DATA.FIFO levels that could be filled. */
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT         0
+#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK          (0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
+
+/* Fields in TEGRA_SPDIF_DATA_OUT */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit        (BIT_MODE=00, PACK=0)
+ * 20-bit        (BIT_MODE=01, PACK=0)
+ * 24-bit        (BIT_MODE=10, PACK=0)
+ * raw           (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ */
+
+#define TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT                     0
+#define TEGRA_SPDIF_DATA_OUT_DATA_16_MASK                      (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT)
+
+#define TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT                     0
+#define TEGRA_SPDIF_DATA_OUT_DATA_20_MASK                      (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT)
+
+#define TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT                     0
+#define TEGRA_SPDIF_DATA_OUT_DATA_24_MASK                      (0xffffff << TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT)
+
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_P                                (1 << 31)
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_C                                (1 << 30)
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_U                                (1 << 29)
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_V                                (1 << 28)
+
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT               8
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK                        (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT                        4
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK                 (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT           0
+#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK            (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT                16
+#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK         (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT         0
+#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK          (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA_SPDIF_DATA_IN */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit        (BIT_MODE=00, PACK=0)
+ * 20-bit        (BIT_MODE=01, PACK=0)
+ * 24-bit        (BIT_MODE=10, PACK=0)
+ * raw           (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ *
+ * Bits 31:24 are common to all modes except 16-bit packed
+ */
+
+#define TEGRA_SPDIF_DATA_IN_DATA_P                             (1 << 31)
+#define TEGRA_SPDIF_DATA_IN_DATA_C                             (1 << 30)
+#define TEGRA_SPDIF_DATA_IN_DATA_U                             (1 << 29)
+#define TEGRA_SPDIF_DATA_IN_DATA_V                             (1 << 28)
+
+#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT                        24
+#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_MASK                 (0xf << TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
+
+#define TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT                      0
+#define TEGRA_SPDIF_DATA_IN_DATA_16_MASK                       (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT)
+
+#define TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT                      0
+#define TEGRA_SPDIF_DATA_IN_DATA_20_MASK                       (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT)
+
+#define TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT                      0
+#define TEGRA_SPDIF_DATA_IN_DATA_24_MASK                       (0xffffff << TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT)
+
+#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT                        8
+#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_MASK                 (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT                 4
+#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_MASK                  (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT            0
+#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK             (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT         16
+#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK          (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT          0
+#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK           (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA_SPDIF_CH_STA_RX_A */
+/* Fields in TEGRA_SPDIF_CH_STA_RX_B */
+/* Fields in TEGRA_SPDIF_CH_STA_RX_C */
+/* Fields in TEGRA_SPDIF_CH_STA_RX_D */
+/* Fields in TEGRA_SPDIF_CH_STA_RX_E */
+/* Fields in TEGRA_SPDIF_CH_STA_RX_F */
+
+/*
+ * The 6-word receive channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of receive is from LSB to MSB
+ * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
+ */
+
+/* Fields in TEGRA_SPDIF_CH_STA_TX_A */
+/* Fields in TEGRA_SPDIF_CH_STA_TX_B */
+/* Fields in TEGRA_SPDIF_CH_STA_TX_C */
+/* Fields in TEGRA_SPDIF_CH_STA_TX_D */
+/* Fields in TEGRA_SPDIF_CH_STA_TX_E */
+/* Fields in TEGRA_SPDIF_CH_STA_TX_F */
+
+/*
+ * The 6-word transmit channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of transmission is from LSB to MSB
+ * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
+ */
+
+/* Fields in TEGRA_SPDIF_USR_STA_RX_A */
+
+/*
+ * This 4-word deep FIFO receives user FIFO field information. The order of
+ * receive is from LSB to MSB bit.
+ */
+
+/* Fields in TEGRA_SPDIF_USR_DAT_TX_A */
+
+/*
+ * This 4-word deep FIFO transmits user FIFO field information. The order of
+ * transmission is from LSB to MSB bit.
+ */
+
+struct tegra_spdif {
+       struct clk *clk_spdif_out;
+       int clk_refs;
+       struct tegra_pcm_dma_params capture_dma_data;
+       struct tegra_pcm_dma_params playback_dma_data;
+       void __iomem *regs;
+       struct dentry *debug;
+       u32 reg_ctrl;
+};
+
+#endif
index 0d6738a..a42e9ac 100644 (file)
@@ -267,7 +267,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
                }
                machine->gpio_requested |= GPIO_HP_MUTE;
 
-               gpio_direction_output(pdata->gpio_hp_mute, 0);
+               gpio_direction_output(pdata->gpio_hp_mute, 1);
        }
 
        if (gpio_is_valid(pdata->gpio_int_mic_en)) {
index f4aa4e0..34aa972 100644 (file)
@@ -288,9 +288,10 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
        snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
-static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-                           struct snd_pcm *pcm)
+static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        struct platform_device *pdev = to_platform_device(dai->platform->dev);
        struct txx9aclc_soc_device *dev;
        struct resource *r;
index 220c616..781d9e6 100644 (file)
@@ -433,9 +433,10 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
  * only at the first time.  the successive calls of this function will
  * append the pcm interface to the corresponding card.
  */
-static void *snd_usb_audio_probe(struct usb_device *dev,
-                                struct usb_interface *intf,
-                                const struct usb_device_id *usb_id)
+static struct snd_usb_audio *
+snd_usb_audio_probe(struct usb_device *dev,
+                   struct usb_interface *intf,
+                   const struct usb_device_id *usb_id)
 {
        const struct snd_usb_audio_quirk *quirk = (const struct snd_usb_audio_quirk *)usb_id->driver_info;
        int i, err;
@@ -540,16 +541,15 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
  * we need to take care of counter, since disconnection can be called also
  * many times as well as usb_audio_probe().
  */
-static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
+static void snd_usb_audio_disconnect(struct usb_device *dev,
+                                    struct snd_usb_audio *chip)
 {
-       struct snd_usb_audio *chip;
        struct snd_card *card;
        struct list_head *p;
 
-       if (ptr == (void *)-1L)
+       if (chip == (void *)-1L)
                return;
 
-       chip = ptr;
        card = chip->card;
        mutex_lock(&register_mutex);
        mutex_lock(&chip->shutdown_mutex);
@@ -585,7 +585,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
 static int usb_audio_probe(struct usb_interface *intf,
                           const struct usb_device_id *id)
 {
-       void *chip;
+       struct snd_usb_audio *chip;
        chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);
        if (chip) {
                usb_set_intfdata(intf, chip);
index b0ef9f5..7c0d21e 100644 (file)
@@ -408,6 +408,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        /* doesn't set the sample rate attribute, but supports it */
                        fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
                        break;
+               case USB_ID(0x0763, 0x2001):  /* M-Audio Quattro USB */
+               case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
                case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
                case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
                                                an older model 77d:223) */
index fb5d68f..67bec76 100644 (file)
@@ -645,7 +645,7 @@ static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream,
        err = snd_pcm_hw_constraint_minmax(substream->runtime,
                                           SNDRV_PCM_HW_PARAM_PERIOD_TIME,
                                           1500000 / ua->packets_per_second,
-                                          8192000);
+                                          UINT_MAX);
        if (err < 0)
                return err;
        err = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
index 0b2ae8e..dba0b7f 100644 (file)
@@ -1677,6 +1677,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       USB_DEVICE(0x0582, 0x011e),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "BOSS", */
+               /* .product_name = "BR-800", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Guillemot devices */
 {
index 090e193..77762c9 100644 (file)
@@ -369,6 +369,30 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
        return 0;
 }
 
+static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev)
+{
+       int err;
+
+       if (dev->actconfig->desc.bConfigurationValue == 1) {
+               snd_printk(KERN_INFO "usb-audio: "
+                          "Fast Track Pro switching to config #2\n");
+               /* This function has to be available by the usb core module.
+                * if it is not avialable the boot quirk has to be left out
+                * and the configuration has to be set by udev or hotplug
+                * rules
+                */
+               err = usb_driver_set_configuration(dev, 2);
+               if (err < 0) {
+                       snd_printdd("error usb_driver_set_configuration: %d\n",
+                                   err);
+                       return -ENODEV;
+               }
+       } else
+               snd_printk(KERN_INFO "usb-audio: Fast Track Pro config OK\n");
+
+       return 0;
+}
+
 /*
  * C-Media CM106/CM106+ have four 16-bit internal registers that are nicely
  * documented in the device's data sheet.
@@ -471,16 +495,49 @@ static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
 /*
  * Setup quirks
  */
-#define AUDIOPHILE_SET                 0x01 /* if set, parse device_setup */
-#define AUDIOPHILE_SET_DTS              0x02 /* if set, enable DTS Digital Output */
-#define AUDIOPHILE_SET_96K              0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */
-#define AUDIOPHILE_SET_24B             0x08 /* 24bits sample if set, 16bits otherwise */
-#define AUDIOPHILE_SET_DI              0x10 /* if set, enable Digital Input */
-#define AUDIOPHILE_SET_MASK            0x1F /* bit mask for setup value */
-#define AUDIOPHILE_SET_24B_48K_DI      0x19 /* value for 24bits+48KHz+Digital Input */
-#define AUDIOPHILE_SET_24B_48K_NOTDI   0x09 /* value for 24bits+48KHz+No Digital Input */
-#define AUDIOPHILE_SET_16B_48K_DI      0x11 /* value for 16bits+48KHz+Digital Input */
-#define AUDIOPHILE_SET_16B_48K_NOTDI   0x01 /* value for 16bits+48KHz+No Digital Input */
+#define MAUDIO_SET             0x01 /* parse device_setup */
+#define MAUDIO_SET_COMPATIBLE  0x80 /* use only "win-compatible" interfaces */
+#define MAUDIO_SET_DTS         0x02 /* enable DTS Digital Output */
+#define MAUDIO_SET_96K         0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */
+#define MAUDIO_SET_24B         0x08 /* 24bits sample if set, 16bits otherwise */
+#define MAUDIO_SET_DI          0x10 /* enable Digital Input */
+#define MAUDIO_SET_MASK                0x1f /* bit mask for setup value */
+#define MAUDIO_SET_24B_48K_DI   0x19 /* 24bits+48KHz+Digital Input */
+#define MAUDIO_SET_24B_48K_NOTDI 0x09 /* 24bits+48KHz+No Digital Input */
+#define MAUDIO_SET_16B_48K_DI   0x11 /* 16bits+48KHz+Digital Input */
+#define MAUDIO_SET_16B_48K_NOTDI 0x01 /* 16bits+48KHz+No Digital Input */
+
+static int quattro_skip_setting_quirk(struct snd_usb_audio *chip,
+                                     int iface, int altno)
+{
+       /* Reset ALL ifaces to 0 altsetting.
+        * Call it for every possible altsetting of every interface.
+        */
+       usb_set_interface(chip->dev, iface, 0);
+       if (chip->setup & MAUDIO_SET) {
+               if (chip->setup & MAUDIO_SET_COMPATIBLE) {
+                       if (iface != 1 && iface != 2)
+                               return 1; /* skip all interfaces but 1 and 2 */
+               } else {
+                       unsigned int mask;
+                       if (iface == 1 || iface == 2)
+                               return 1; /* skip interfaces 1 and 2 */
+                       if ((chip->setup & MAUDIO_SET_96K) && altno != 1)
+                               return 1; /* skip this altsetting */
+                       mask = chip->setup & MAUDIO_SET_MASK;
+                       if (mask == MAUDIO_SET_24B_48K_DI && altno != 2)
+                               return 1; /* skip this altsetting */
+                       if (mask == MAUDIO_SET_24B_48K_NOTDI && altno != 3)
+                               return 1; /* skip this altsetting */
+                       if (mask == MAUDIO_SET_16B_48K_NOTDI && altno != 4)
+                               return 1; /* skip this altsetting */
+               }
+       }
+       snd_printdd(KERN_INFO
+                   "using altsetting %d for interface %d config %d\n",
+                   altno, iface, chip->setup);
+       return 0; /* keep this altsetting */
+}
 
 static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
                                         int iface,
@@ -491,30 +548,65 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
         */
        usb_set_interface(chip->dev, iface, 0);
 
-       if (chip->setup & AUDIOPHILE_SET) {
-               if ((chip->setup & AUDIOPHILE_SET_DTS)
-                   && altno != 6)
+       if (chip->setup & MAUDIO_SET) {
+               unsigned int mask;
+               if ((chip->setup & MAUDIO_SET_DTS) && altno != 6)
                        return 1; /* skip this altsetting */
-               if ((chip->setup & AUDIOPHILE_SET_96K)
-                   && altno != 1)
+               if ((chip->setup & MAUDIO_SET_96K) && altno != 1)
                        return 1; /* skip this altsetting */
-               if ((chip->setup & AUDIOPHILE_SET_MASK) ==
-                   AUDIOPHILE_SET_24B_48K_DI && altno != 2)
+               mask = chip->setup & MAUDIO_SET_MASK;
+               if (mask == MAUDIO_SET_24B_48K_DI && altno != 2)
                        return 1; /* skip this altsetting */
-               if ((chip->setup & AUDIOPHILE_SET_MASK) ==
-                   AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3)
+               if (mask == MAUDIO_SET_24B_48K_NOTDI && altno != 3)
                        return 1; /* skip this altsetting */
-               if ((chip->setup & AUDIOPHILE_SET_MASK) ==
-                   AUDIOPHILE_SET_16B_48K_DI && altno != 4)
+               if (mask == MAUDIO_SET_16B_48K_DI && altno != 4)
                        return 1; /* skip this altsetting */
-               if ((chip->setup & AUDIOPHILE_SET_MASK) ==
-                   AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5)
+               if (mask == MAUDIO_SET_16B_48K_NOTDI && altno != 5)
                        return 1; /* skip this altsetting */
        }
 
        return 0; /* keep this altsetting */
 }
 
+
+static int fasttrackpro_skip_setting_quirk(struct snd_usb_audio *chip,
+                                          int iface, int altno)
+{
+       /* Reset ALL ifaces to 0 altsetting.
+        * Call it for every possible altsetting of every interface.
+        */
+       usb_set_interface(chip->dev, iface, 0);
+
+       /* possible configuration where both inputs and only one output is
+        *used is not supported by the current setup
+        */
+       if (chip->setup & (MAUDIO_SET | MAUDIO_SET_24B)) {
+               if (chip->setup & MAUDIO_SET_96K) {
+                       if (altno != 3 && altno != 6)
+                               return 1;
+               } else if (chip->setup & MAUDIO_SET_DI) {
+                       if (iface == 4)
+                               return 1; /* no analog input */
+                       if (altno != 2 && altno != 5)
+                               return 1; /* enable only altsets 2 and 5 */
+               } else {
+                       if (iface == 5)
+                               return 1; /* disable digialt input */
+                       if (altno != 2 && altno != 5)
+                               return 1; /* enalbe only altsets 2 and 5 */
+               }
+       } else {
+               /* keep only 16-Bit mode */
+               if (altno != 1)
+                       return 1;
+       }
+
+       snd_printdd(KERN_INFO
+                   "using altsetting %d for interface %d config %d\n",
+                   altno, iface, chip->setup);
+       return 0; /* keep this altsetting */
+}
+
 int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,
                                  int iface,
                                  int altno)
@@ -522,6 +614,12 @@ int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,
        /* audiophile usb: skip altsets incompatible with device_setup */
        if (chip->usb_id == USB_ID(0x0763, 0x2003))
                return audiophile_skip_setting_quirk(chip, iface, altno);
+       /* quattro usb: skip altsets incompatible with device_setup */
+       if (chip->usb_id == USB_ID(0x0763, 0x2001))
+               return quattro_skip_setting_quirk(chip, iface, altno);
+       /* fasttrackpro usb: skip altsets incompatible with device_setup */
+       if (chip->usb_id == USB_ID(0x0763, 0x2012))
+               return fasttrackpro_skip_setting_quirk(chip, iface, altno);
 
        return 0;
 }
@@ -560,6 +658,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
        case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */
        case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */
                return snd_usb_nativeinstruments_boot_quirk(dev);
+       case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
+               return snd_usb_fasttrackpro_boot_quirk(dev);
        }
 
        return 0;
@@ -570,15 +670,24 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
  */
 int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp)
 {
+       /* it depends on altsetting wether the device is big-endian or not */
        switch (chip->usb_id) {
        case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */
-               if (fp->endpoint & USB_DIR_IN)
+               if (fp->altsetting == 2 || fp->altsetting == 3 ||
+                       fp->altsetting == 5 || fp->altsetting == 6)
                        return 1;
                break;
        case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
                if (chip->setup == 0x00 ||
-                   fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3)
+                       fp->altsetting == 1 || fp->altsetting == 2 ||
+                       fp->altsetting == 3)
+                       return 1;
+               break;
+       case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro */
+               if (fp->altsetting == 2 || fp->altsetting == 3 ||
+                       fp->altsetting == 5 || fp->altsetting == 6)
                        return 1;
+               break;
        }
        return 0;
 }