Merge tag 'asoc-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next

ASoC: Additional updates for v3.7

A couple more updates for 3.7, enhancements to the ux500 and wm2000
drivers, a new driver for DA9055 and the support for regulator bypass
mode.  With the exception of the DA9055 this has all had a chance to
soak in -next (the driver was added on Friday so should be in -next
today).
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 4e4d0bc..d90d8ec 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -860,8 +860,14 @@
 
     [Multiple options for each card instance]
     model	- force the model name
-    position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF,
-    		   3 = VIACOMBO, 4 = COMBO)
+    position_fix - Fix DMA pointer
+		  -1 = system default: choose appropriate one per controller
+			hardware
+		  0 = auto: falls back to LPIB when POSBUF doesn't work
+		  1 = use LPIB
+		  2 = POSBUF: use position buffer
+		  3 = VIACOMBO: VIA-specific workaround for capture
+		  4 = COMBO: use LPIB for playback, auto for capture stream
     probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
     		  When the bit 8 (0x100) is set, the lower 8 bits are used
 		  as the "fixed" codec slots; i.e. the driver probes the
diff --git a/Documentation/sound/alsa/Channel-Mapping-API.txt b/Documentation/sound/alsa/Channel-Mapping-API.txt
new file mode 100644
index 0000000..3c43d1a
--- /dev/null
+++ b/Documentation/sound/alsa/Channel-Mapping-API.txt
@@ -0,0 +1,153 @@
+ALSA PCM channel-mapping API
+============================
+					Takashi Iwai <tiwai@suse.de>
+
+GENERAL
+-------
+
+The channel mapping API allows user to query the possible channel maps
+and the current channel map, also optionally to modify the channel map
+of the current stream.
+
+A channel map is an array of position for each PCM channel.
+Typically, a stereo PCM stream has a channel map of
+  { front_left, front_right }
+while a 4.0 surround PCM stream has a channel map of
+  { front left, front right, rear left, rear right }.
+
+The problem, so far, was that we had no standard channel map
+explicitly, and applications had no way to know which channel
+corresponds to which (speaker) position.  Thus, applications applied
+wrong channels for 5.1 outputs, and you hear suddenly strange sound
+from rear.  Or, some devices secretly assume that center/LFE is the
+third/fourth channels while others that C/LFE as 5th/6th channels.
+
+Also, some devices such as HDMI are configurable for different speaker
+positions even with the same number of total channels.  However, there
+was no way to specify this because of lack of channel map
+specification.  These are the main motivations for the new channel
+mapping API.
+
+
+DESIGN
+------
+
+Actually, "the channel mapping API" doesn't introduce anything new in
+the kernel/user-space ABI perspective.  It uses only the existing
+control element features.
+
+As a ground design, each PCM substream may contain a control element
+providing the channel mapping information and configuration.  This
+element is specified by:
+	iface = SNDRV_CTL_ELEM_IFACE_PCM
+	name = "Playback Channel Map" or "Capture Channel Map"
+	device = the same device number for the assigned PCM substream
+	index = the same index number for the assigned PCM substream
+
+Note the name is different depending on the PCM substream direction.
+
+Each control element provides at least the TLV read operation and the
+read operation.  Optionally, the write operation can be provided to
+allow user to change the channel map dynamically.
+
+* TLV
+
+The TLV operation gives the list of available channel
+maps.  A list item of a channel map is usually a TLV of
+	type data-bytes ch0 ch1 ch2...
+where type is the TLV type value, the second argument is the total
+bytes (not the numbers) of channel values, and the rest are the
+position value for each channel.
+
+As a TLV type, either SNDRV_CTL_TLVT_CHMAP_FIXED,
+SNDRV_CTL_TLV_CHMAP_VAR or SNDRV_CTL_TLVT_CHMAP_PAIRED can be used.
+The _FIXED type is for a channel map with the fixed channel position
+while the latter two are for flexible channel positions.  _VAR type is
+for a channel map where all channels are freely swappable and _PAIRED
+type is where pair-wise channels are swappable.  For example, when you
+have {FL/FR/RL/RR} channel map, _PAIRED type would allow you to swap
+only {RL/RR/FL/FR} while _VAR type would allow even swapping FL and
+RR.
+
+These new TLV types are defined in sound/tlv.h.
+
+The available channel position values are defined in sound/asound.h,
+here is a cut:
+
+/* channel positions */
+enum {
+	SNDRV_CHMAP_UNKNOWN = 0,
+	SNDRV_CHMAP_NA,		/* N/A, silent */
+	SNDRV_CHMAP_MONO,	/* mono stream */
+	/* this follows the alsa-lib mixer channel value + 3 */
+	SNDRV_CHMAP_FL,		/* front left */
+	SNDRV_CHMAP_FR,		/* front right */
+	SNDRV_CHMAP_RL,		/* rear left */
+	SNDRV_CHMAP_RR,		/* rear right */
+	SNDRV_CHMAP_FC,		/* front center */
+	SNDRV_CHMAP_LFE,	/* LFE */
+	SNDRV_CHMAP_SL,		/* side left */
+	SNDRV_CHMAP_SR,		/* side right */
+	SNDRV_CHMAP_RC,		/* rear center */
+	/* new definitions */
+	SNDRV_CHMAP_FLC,	/* front left center */
+	SNDRV_CHMAP_FRC,	/* front right center */
+	SNDRV_CHMAP_RLC,	/* rear left center */
+	SNDRV_CHMAP_RRC,	/* rear right center */
+	SNDRV_CHMAP_FLW,	/* front left wide */
+	SNDRV_CHMAP_FRW,	/* front right wide */
+	SNDRV_CHMAP_FLH,	/* front left high */
+	SNDRV_CHMAP_FCH,	/* front center high */
+	SNDRV_CHMAP_FRH,	/* front right high */
+	SNDRV_CHMAP_TC,		/* top center */
+	SNDRV_CHMAP_TFL,	/* top front left */
+	SNDRV_CHMAP_TFR,	/* top front right */
+	SNDRV_CHMAP_TFC,	/* top front center */
+	SNDRV_CHMAP_TRL,	/* top rear left */
+	SNDRV_CHMAP_TRR,	/* top rear right */
+	SNDRV_CHMAP_TRC,	/* top rear center */
+	SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC,
+};
+
+When a PCM stream can provide more than one channel map, you can
+provide multiple channel maps in a TLV container type.  The TLV data
+to be returned will contain such as:
+	SNDRV_CTL_TLVT_CONTAINER 96
+	    SNDRV_CTL_TLVT_CHMAP_FIXED 4 SNDRV_CHMAP_FC
+	    SNDRV_CTL_TLVT_CHMAP_FIXED 8 SNDRV_CHMAP_FL SNDRV_CHMAP_FR
+	    SNDRV_CTL_TLVT_CHMAP_FIXED 16 NDRV_CHMAP_FL SNDRV_CHMAP_FR \
+		SNDRV_CHMAP_RL SNDRV_CHMAP_RR
+
+The channel position is provided in LSB 16bits.  The upper bits are
+used for bit flags.
+
+#define SNDRV_CHMAP_POSITION_MASK	0xffff
+#define SNDRV_CHMAP_PHASE_INVERSE	(0x01 << 16)
+#define SNDRV_CHMAP_DRIVER_SPEC		(0x02 << 16)
+
+SNDRV_CHMAP_PHASE_INVERSE indicates the channel is phase inverted,
+(thus summing left and right channels would result in almost silence).
+Some digital mic devices have this.
+
+When SNDRV_CHMAP_DRIVER_SPEC is set, all the channel position values
+don't follow the standard definition above but driver-specific.
+
+* READ OPERATION
+
+The control read operation is for providing the current channel map of
+the given stream.  The control element returns an integer array
+containing the position of each channel.
+
+When this is performed before the number of the channel is specified
+(i.e. hw_params is set), it should return all channels set to
+UNKNOWN.
+
+* WRITE OPERATION
+
+The control write operation is optional, and only for devices that can
+change the channel configuration on the fly, such as HDMI.  User needs
+to pass an integer value containing the valid channel positions for
+all channels of the assigned PCM substream.
+
+This operation is allowed only at PCM PREPARED state.  When called in
+other states, it shall return an error.
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index a92bba8..16dfe57 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -74,7 +74,8 @@
 
 AD1882 / AD1882A
 ================
-  3stack	3-stack mode (default)
+  3stack	3-stack mode
+  3stack-automute 3-stack with automute front HP (default)
   6stack	6-stack mode
 
 AD1884A / AD1883 / AD1984A / AD1984B
diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c
index c38d754..d088afa0 100644
--- a/arch/arm/plat-samsung/dma-ops.c
+++ b/arch/arm/plat-samsung/dma-ops.c
@@ -91,7 +91,8 @@
 		break;
 	case DMA_CYCLIC:
 		desc = dmaengine_prep_dma_cyclic(chan, param->buf,
-			param->len, param->period, param->direction);
+			param->len, param->period, param->direction,
+			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 		break;
 	default:
 		dev_err(&chan->dev->device, "unsupported format\n");
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 09da4e5..d3201e4 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -653,7 +653,8 @@
 
 static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
 		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
-		size_t period_len, enum dma_transfer_direction dir)
+		size_t period_len, enum dma_transfer_direction dir,
+		unsigned long flags)
 {
 	return chan->device->device_prep_dma_cyclic(chan, buf_addr, buf_len,
 						period_len, dir, flags, NULL);
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 02cbb50..4458b87 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -422,6 +422,7 @@
  */
 
 struct snd_ac97;
+struct snd_pcm_chmap;
 
 struct snd_ac97_build_ops {
 	int (*build_3d) (struct snd_ac97 *ac97);
@@ -528,6 +529,8 @@
 	struct delayed_work power_work;
 #endif
 	struct device dev;
+
+	struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */
 };
 
 #define to_ac97_t(d) container_of(d, struct snd_ac97, dev)
diff --git a/include/sound/ad1816a.h b/include/sound/ad1816a.h
index d010858..2a89f0d 100644
--- a/include/sound/ad1816a.h
+++ b/include/sound/ad1816a.h
@@ -147,6 +147,9 @@
 	unsigned int c_dma_size;
 
 	struct snd_timer *timer;
+#ifdef CONFIG_PM
+	unsigned short image[48];
+#endif
 };
 
 
@@ -165,11 +168,15 @@
 
 extern int snd_ad1816a_create(struct snd_card *card, unsigned long port,
 			      int irq, int dma1, int dma2,
-			      struct snd_ad1816a **chip);
+			      struct snd_ad1816a *chip);
 
 extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm);
 extern int snd_ad1816a_mixer(struct snd_ad1816a *chip);
 extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
 			     struct snd_timer **rtimer);
+#ifdef CONFIG_PM
+extern void snd_ad1816a_suspend(struct snd_ad1816a *chip);
+extern void snd_ad1816a_resume(struct snd_ad1816a *chip);
+#endif
 
 #endif	/* __SOUND_AD1816A_H */
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 0876a1e..dfe7d44 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -472,6 +472,45 @@
 	SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
 };
 
+/* channel positions */
+enum {
+	SNDRV_CHMAP_UNKNOWN = 0,
+	SNDRV_CHMAP_NA,		/* N/A, silent */
+	SNDRV_CHMAP_MONO,	/* mono stream */
+	/* this follows the alsa-lib mixer channel value + 3 */
+	SNDRV_CHMAP_FL,		/* front left */
+	SNDRV_CHMAP_FR,		/* front right */
+	SNDRV_CHMAP_RL,		/* rear left */
+	SNDRV_CHMAP_RR,		/* rear right */
+	SNDRV_CHMAP_FC,		/* front center */
+	SNDRV_CHMAP_LFE,	/* LFE */
+	SNDRV_CHMAP_SL,		/* side left */
+	SNDRV_CHMAP_SR,		/* side right */
+	SNDRV_CHMAP_RC,		/* rear center */
+	/* new definitions */
+	SNDRV_CHMAP_FLC,	/* front left center */
+	SNDRV_CHMAP_FRC,	/* front right center */
+	SNDRV_CHMAP_RLC,	/* rear left center */
+	SNDRV_CHMAP_RRC,	/* rear right center */
+	SNDRV_CHMAP_FLW,	/* front left wide */
+	SNDRV_CHMAP_FRW,	/* front right wide */
+	SNDRV_CHMAP_FLH,	/* front left high */
+	SNDRV_CHMAP_FCH,	/* front center high */
+	SNDRV_CHMAP_FRH,	/* front right high */
+	SNDRV_CHMAP_TC,		/* top center */
+	SNDRV_CHMAP_TFL,	/* top front left */
+	SNDRV_CHMAP_TFR,	/* top front right */
+	SNDRV_CHMAP_TFC,	/* top front center */
+	SNDRV_CHMAP_TRL,	/* top rear left */
+	SNDRV_CHMAP_TRR,	/* top rear right */
+	SNDRV_CHMAP_TRC,	/* top rear center */
+	SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC,
+};
+
+#define SNDRV_CHMAP_POSITION_MASK	0xffff
+#define SNDRV_CHMAP_PHASE_INVERSE	(0x01 << 16)
+#define SNDRV_CHMAP_DRIVER_SPEC		(0x02 << 16)
+
 #define SNDRV_PCM_IOCTL_PVERSION	_IOR('A', 0x00, int)
 #define SNDRV_PCM_IOCTL_INFO		_IOR('A', 0x01, struct snd_pcm_info)
 #define SNDRV_PCM_IOCTL_TSTAMP		_IOW('A', 0x02, int)
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
index da4a456..602dc6c 100644
--- a/include/sound/compress_params.h
+++ b/include/sound/compress_params.h
@@ -72,6 +72,7 @@
 #define SND_AUDIOCODEC_IEC61937              ((__u32) 0x0000000B)
 #define SND_AUDIOCODEC_G723_1                ((__u32) 0x0000000C)
 #define SND_AUDIOCODEC_G729                  ((__u32) 0x0000000D)
+#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_G729
 
 /*
  * Profile and modes are listed with bit masks. This allows for a
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 4f865df..1a33f48 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1788,7 +1788,7 @@
 	unsigned int efx_voices_mask[2];
 	unsigned int next_free_voice;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	unsigned int *saved_ptr;
 	unsigned int *saved_gpr;
 	unsigned int *tram_val_saved;
@@ -1856,7 +1856,7 @@
 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data);
 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu);
 void snd_emu10k1_resume_init(struct snd_emu10k1 *emu);
 void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu);
diff --git a/include/sound/initval.h b/include/sound/initval.h
index f99a0d2..ac62c67 100644
--- a/include/sound/initval.h
+++ b/include/sound/initval.h
@@ -50,6 +50,20 @@
 #define SNDRV_DEFAULT_DMA_SIZE	{ [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA_SIZE }
 #define SNDRV_DEFAULT_PTR	SNDRV_DEFAULT_STR
 
+#ifdef SNDRV_LEGACY_FIND_FREE_IOPORT
+static long snd_legacy_find_free_ioport(long *port_table, long size)
+{
+	while (*port_table != -1) {
+		if (request_region(*port_table, size, "ALSA test")) {
+			release_region(*port_table, size);
+			return *port_table;
+		}
+		port_table++;
+	}
+	return -1;
+}
+#endif
+
 #ifdef SNDRV_LEGACY_FIND_FREE_IRQ
 #include <linux/interrupt.h>
 
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index c425062..844af65 100644
--- a/include/sound/memalloc.h
+++ b/include/sound/memalloc.h
@@ -98,8 +98,10 @@
 /*
  * return the physical address at the corresponding offset
  */
-static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
+static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab,
+					   size_t offset)
 {
+	struct snd_sg_buf *sgbuf = dmab->private_data;
 	dma_addr_t addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
 	addr &= PAGE_MASK;
 	return addr + offset % PAGE_SIZE;
@@ -108,10 +110,31 @@
 /*
  * return the virtual address at the corresponding offset
  */
-static inline void *snd_sgbuf_get_ptr(struct snd_sg_buf *sgbuf, size_t offset)
+static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab,
+				     size_t offset)
 {
+	struct snd_sg_buf *sgbuf = dmab->private_data;
 	return sgbuf->table[offset >> PAGE_SHIFT].buf + offset % PAGE_SIZE;
 }
+
+unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
+				      unsigned int ofs, unsigned int size);
+#else
+/* non-SG versions */
+static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab,
+					    size_t offset)
+{
+	return dmab->addr + offset;
+}
+
+static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab,
+				      size_t offset)
+{
+	return dmab->area + offset;
+}
+
+#define snd_sgbuf_get_chunk_size(dmab, ofs, size)	(size)
+
 #endif /* CONFIG_SND_DMA_SGBUF */
 
 /* allocate/release a buffer */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index cdca2ab..7e4e4e3 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -437,6 +437,7 @@
 	struct snd_info_entry *proc_xrun_debug_entry;
 #endif
 #endif
+	struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
 };
 
 struct snd_pcm {
@@ -982,53 +983,42 @@
 	_snd_pcm_lib_alloc_vmalloc_buffer \
 			(subs, size, GFP_KERNEL | GFP_DMA32 | __GFP_ZERO)
 
+#define snd_pcm_get_dma_buf(substream) ((substream)->runtime->dma_buffer_p)
+
 #ifdef CONFIG_SND_DMA_SGBUF
 /*
  * SG-buffer handling
  */
 #define snd_pcm_substream_sgbuf(substream) \
-	((substream)->runtime->dma_buffer_p->private_data)
-
-static inline dma_addr_t
-snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
-{
-	struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
-	return snd_sgbuf_get_addr(sg, ofs);
-}
-
-static inline void *
-snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
-{
-	struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
-	return snd_sgbuf_get_ptr(sg, ofs);
-}
+	snd_pcm_get_dma_buf(substream)->private_data
 
 struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
 				    unsigned long offset);
-unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
-					  unsigned int ofs, unsigned int size);
-
 #else /* !SND_DMA_SGBUF */
 /*
  * fake using a continuous buffer
  */
+#define snd_pcm_sgbuf_ops_page	NULL
+#endif /* SND_DMA_SGBUF */
+
 static inline dma_addr_t
 snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
 {
-	return substream->runtime->dma_addr + ofs;
+	return snd_sgbuf_get_addr(snd_pcm_get_dma_buf(substream), ofs);
 }
 
 static inline void *
 snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
 {
-	return substream->runtime->dma_area + ofs;
+	return snd_sgbuf_get_ptr(snd_pcm_get_dma_buf(substream), ofs);
 }
 
-#define snd_pcm_sgbuf_ops_page	NULL
-
-#define snd_pcm_sgbuf_get_chunk_size(subs, ofs, size)	(size)
-
-#endif /* SND_DMA_SGBUF */
+static inline unsigned int
+snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
+			     unsigned int ofs, unsigned int size)
+{
+	return snd_sgbuf_get_chunk_size(snd_pcm_get_dma_buf(substream), ofs, size);
+}
 
 /* handle mmap counter - PCM mmap callback should handle this counter properly */
 static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
@@ -1086,4 +1076,51 @@
 		return "Capture";
 }
 
+/*
+ * PCM channel-mapping control API
+ */
+/* array element of channel maps */
+struct snd_pcm_chmap_elem {
+	unsigned char channels;
+	unsigned char map[15];
+};
+
+/* channel map information; retrieved via snd_kcontrol_chip() */
+struct snd_pcm_chmap {
+	struct snd_pcm *pcm;	/* assigned PCM instance */
+	int stream;		/* PLAYBACK or CAPTURE */
+	struct snd_kcontrol *kctl;
+	const struct snd_pcm_chmap_elem *chmap;
+	unsigned int max_channels;
+	unsigned int channel_mask;	/* optional: active channels bitmask */
+	void *private_data;	/* optional: private data pointer */
+};
+
+/* get the PCM substream assigned to the given chmap info */
+static inline struct snd_pcm_substream *
+snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx)
+{
+	struct snd_pcm_substream *s;
+	for (s = info->pcm->streams[info->stream].substream; s; s = s->next)
+		if (s->number == idx)
+			return s;
+	return NULL;
+}
+
+/* ALSA-standard channel maps (RL/RR prior to C/LFE) */
+extern const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[];
+/* Other world's standard channel maps (C/LFE prior to RL/RR) */
+extern const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[];
+
+/* bit masks to be passed to snd_pcm_chmap.channel_mask field */
+#define SND_PCM_CHMAP_MASK_24	((1U << 2) | (1U << 4))
+#define SND_PCM_CHMAP_MASK_246	(SND_PCM_CHMAP_MASK_24 | (1U << 6))
+#define SND_PCM_CHMAP_MASK_2468	(SND_PCM_CHMAP_MASK_246 | (1U << 8))
+
+int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
+			   const struct snd_pcm_chmap_elem *chmap,
+			   int max_channels,
+			   unsigned long private_value,
+			   struct snd_pcm_chmap **info_ret);
+
 #endif /* __SOUND_PCM_H */
diff --git a/include/sound/tlv.h b/include/sound/tlv.h
index a64d8fe..28c65e1 100644
--- a/include/sound/tlv.h
+++ b/include/sound/tlv.h
@@ -86,4 +86,12 @@
 
 #define TLV_DB_GAIN_MUTE	-9999999
 
+/*
+ * channel-mapping TLV items
+ *  TLV length must match with num_channels
+ */
+#define SNDRV_CTL_TLVT_CHMAP_FIXED	0x101	/* fixed channel position */
+#define SNDRV_CTL_TLVT_CHMAP_VAR	0x102	/* channels freely swappable */
+#define SNDRV_CTL_TLVT_CHMAP_PAIRED	0x103	/* pair-wise swappable */
+
 #endif /* __SOUND_TLV_H */
diff --git a/include/sound/version.h b/include/sound/version.h
deleted file mode 100644
index cc75024..0000000
--- a/include/sound/version.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/* include/version.h */
-#define CONFIG_SND_VERSION "1.0.25"
-#define CONFIG_SND_DATE ""
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index eb60cb8d..c40ae57 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -425,6 +425,26 @@
 	return 0;
 }
 
+static int snd_compress_check_input(struct snd_compr_params *params)
+{
+	/* first let's check the buffer parameter's */
+	if (params->buffer.fragment_size == 0 ||
+			params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size)
+		return -EINVAL;
+
+	/* now codec parameters */
+	if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX)
+		return -EINVAL;
+
+	if (params->codec.ch_in == 0 || params->codec.ch_out == 0)
+		return -EINVAL;
+
+	if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000))
+		return -EINVAL;
+
+	return 0;
+}
+
 static int
 snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
 {
@@ -443,11 +463,17 @@
 			retval = -EFAULT;
 			goto out;
 		}
+
+		retval = snd_compress_check_input(params);
+		if (retval)
+			goto out;
+
 		retval = snd_compr_allocate_buffer(stream, params);
 		if (retval) {
 			retval = -ENOMEM;
 			goto out;
 		}
+
 		retval = stream->ops->set_params(stream, params);
 		if (retval)
 			goto out;
diff --git a/sound/core/control.c b/sound/core/control.c
index 2487a6b..7e86a5b 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -246,6 +246,7 @@
 	kctl.count = ncontrol->count ? ncontrol->count : 1;
 	access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
 		 (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
+				      SNDRV_CTL_ELEM_ACCESS_VOLATILE|
 				      SNDRV_CTL_ELEM_ACCESS_INACTIVE|
 				      SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
 				      SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
diff --git a/sound/core/info.c b/sound/core/info.c
index c1e611c..6b368d2 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -28,7 +28,7 @@
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/info.h>
-#include <sound/version.h>
+#include <linux/utsname.h>
 #include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include <stdarg.h>
@@ -986,9 +986,8 @@
 static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
 	snd_iprintf(buffer,
-		    "Advanced Linux Sound Architecture Driver Version "
-		    CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"
-		   );
+		    "Advanced Linux Sound Architecture Driver Version k%s.\n",
+		    init_utsname()->release);
 }
 
 static int __init snd_info_version_init(void)
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index cf42ab5..83c29db 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -26,7 +26,6 @@
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/info.h>
-#include <sound/version.h>
 #include <linux/utsname.h>
 #include <linux/mutex.h>
 
@@ -94,7 +93,7 @@
 static void snd_sndstat_proc_read(struct snd_info_entry *entry,
 				  struct snd_info_buffer *buffer)
 {
-	snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n");
+	snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA emulation code)\n");
 	snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n",
 		    init_utsname()->sysname,
 		    init_utsname()->nodename,
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 18297f7..29f6ded 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1046,6 +1046,7 @@
 			
 		if (kctl->info(kctl, uinfo)) {
 			up_read(&mixer->card->controls_rwsem);
+			kfree(uinfo);
 			return 0;
 		}
 		strcpy(str, ptr->name);
@@ -1061,6 +1062,7 @@
 				uinfo->value.enumerated.item = slot.capture_item;
 				if (kctl->info(kctl, uinfo)) {
 					up_read(&mixer->card->controls_rwsem);
+					kfree(uinfo);
 					return 0;
 				}
 				if (!strcmp(uinfo->value.enumerated.name, str)) {
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 1a3070b..f299194 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1105,6 +1105,10 @@
 			break;
 		}
 		snd_unregister_device(devtype, pcm->card, pcm->device);
+		if (pcm->streams[cidx].chmap_kctl) {
+			snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
+			pcm->streams[cidx].chmap_kctl = NULL;
+		}
 	}
  unlock:
 	mutex_unlock(&register_mutex);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 7ae6719..f42c10a 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -26,6 +26,7 @@
 #include <linux/export.h>
 #include <sound/core.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -2302,3 +2303,216 @@
 }
 
 EXPORT_SYMBOL(snd_pcm_lib_readv);
+
+/*
+ * standard channel mapping helpers
+ */
+
+/* default channel maps for multi-channel playbacks, up to 8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[] = {
+	{ .channels = 1,
+	  .map = { SNDRV_CHMAP_MONO } },
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+	{ .channels = 4,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ .channels = 6,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+	{ .channels = 8,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+	{ }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_std_chmaps);
+
+/* alternative channel maps with CLFE <-> surround swapped for 6/8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[] = {
+	{ .channels = 1,
+	  .map = { SNDRV_CHMAP_MONO } },
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+	{ .channels = 4,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ .channels = 6,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ .channels = 8,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+	{ }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_alt_chmaps);
+
+static bool valid_chmap_channels(const struct snd_pcm_chmap *info, int ch)
+{
+	if (ch > info->max_channels)
+		return false;
+	return !info->channel_mask || (info->channel_mask & (1U << ch));
+}
+
+static int pcm_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *uinfo)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 0;
+	uinfo->count = info->max_channels;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+	return 0;
+}
+
+/* get callback for channel map ctl element
+ * stores the channel position firstly matching with the current channels
+ */
+static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	struct snd_pcm_substream *substream;
+	const struct snd_pcm_chmap_elem *map;
+
+	if (snd_BUG_ON(!info->chmap))
+		return -EINVAL;
+	substream = snd_pcm_chmap_substream(info, idx);
+	if (!substream)
+		return -ENODEV;
+	memset(ucontrol->value.integer.value, 0,
+	       sizeof(ucontrol->value.integer.value));
+	if (!substream->runtime)
+		return 0; /* no channels set */
+	for (map = info->chmap; map->channels; map++) {
+		int i;
+		if (map->channels == substream->runtime->channels &&
+		    valid_chmap_channels(info, map->channels)) {
+			for (i = 0; i < map->channels; i++)
+				ucontrol->value.integer.value[i] = map->map[i];
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+/* tlv callback for channel map ctl element
+ * expands the pre-defined channel maps in a form of TLV
+ */
+static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+			     unsigned int size, unsigned int __user *tlv)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	const struct snd_pcm_chmap_elem *map;
+	unsigned int __user *dst;
+	int c, count = 0;
+
+	if (snd_BUG_ON(!info->chmap))
+		return -EINVAL;
+	if (size < 8)
+		return -ENOMEM;
+	if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+		return -EFAULT;
+	size -= 8;
+	dst = tlv + 2;
+	for (map = info->chmap; map->channels; map++) {
+		int chs_bytes = map->channels * 4;
+		if (!valid_chmap_channels(info, map->channels))
+			continue;
+		if (size < 8)
+			return -ENOMEM;
+		if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
+		    put_user(chs_bytes, dst + 1))
+			return -EFAULT;
+		dst += 2;
+		size -= 8;
+		count += 8;
+		if (size < chs_bytes)
+			return -ENOMEM;
+		size -= chs_bytes;
+		count += chs_bytes;
+		for (c = 0; c < map->channels; c++) {
+			if (put_user(map->map[c], dst))
+				return -EFAULT;
+			dst++;
+		}
+	}
+	if (put_user(count, tlv + 1))
+		return -EFAULT;
+	return 0;
+}
+
+static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	info->pcm->streams[info->stream].chmap_kctl = NULL;
+	kfree(info);
+}
+
+/**
+ * snd_pcm_add_chmap_ctls - create channel-mapping control elements
+ * @pcm: the assigned PCM instance
+ * @stream: stream direction
+ * @chmap: channel map elements (for query)
+ * @max_channels: the max number of channels for the stream
+ * @private_value: the value passed to each kcontrol's private_value field
+ * @info_ret: store struct snd_pcm_chmap instance if non-NULL
+ *
+ * Create channel-mapping control elements assigned to the given PCM stream(s).
+ * Returns zero if succeed, or a negative error value.
+ */
+int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
+			   const struct snd_pcm_chmap_elem *chmap,
+			   int max_channels,
+			   unsigned long private_value,
+			   struct snd_pcm_chmap **info_ret)
+{
+	struct snd_pcm_chmap *info;
+	struct snd_kcontrol_new knew = {
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+		.info = pcm_chmap_ctl_info,
+		.get = pcm_chmap_ctl_get,
+		.tlv.c = pcm_chmap_ctl_tlv,
+	};
+	int err;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	info->pcm = pcm;
+	info->stream = stream;
+	info->chmap = chmap;
+	info->max_channels = max_channels;
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		knew.name = "Playback Channel Map";
+	else
+		knew.name = "Capture Channel Map";
+	knew.device = pcm->device;
+	knew.count = pcm->streams[stream].substream_count;
+	knew.private_value = private_value;
+	info->kctl = snd_ctl_new1(&knew, info);
+	if (!info->kctl) {
+		kfree(info);
+		return -ENOMEM;
+	}
+	info->kctl->private_free = pcm_chmap_ctl_private_free;
+	err = snd_ctl_add(pcm->card, info->kctl);
+	if (err < 0)
+		return err;
+	pcm->streams[stream].chmap_kctl = info->kctl;
+	if (info_ret)
+		*info_ret = info;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index 9571313..69e01c4 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -327,32 +327,6 @@
 }
 
 EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
-
-/*
- * compute the max chunk size with continuous pages on sg-buffer
- */
-unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
-					  unsigned int ofs, unsigned int size)
-{
-	struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
-	unsigned int start, end, pg;
-
-	start = ofs >> PAGE_SHIFT;
-	end = (ofs + size - 1) >> PAGE_SHIFT;
-	/* check page continuity */
-	pg = sg->table[start].addr >> PAGE_SHIFT;
-	for (;;) {
-		start++;
-		if (start > end)
-			break;
-		pg++;
-		if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
-			return (start << PAGE_SHIFT) - ofs;
-	}
-	/* ok, all on continuous pages */
-	return size;
-}
-EXPORT_SYMBOL(snd_pcm_sgbuf_get_chunk_size);
 #endif /* CONFIG_SND_DMA_SGBUF */
 
 /**
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 5cf8d65e..60e8fc1 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -569,5 +569,7 @@
 EXPORT_SYMBOL(snd_seq_device_new);
 EXPORT_SYMBOL(snd_seq_device_register_driver);
 EXPORT_SYMBOL(snd_seq_device_unregister_driver);
+#ifdef CONFIG_MODULES
 EXPORT_SYMBOL(snd_seq_autoload_lock);
 EXPORT_SYMBOL(snd_seq_autoload_unlock);
+#endif
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index d0f0035..0a41850 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
+#include <linux/export.h>
 #include <sound/memalloc.h>
 
 
@@ -136,3 +137,29 @@
 	snd_free_sgbuf_pages(dmab); /* free the table */
 	return NULL;
 }
+
+/*
+ * compute the max chunk size with continuous pages on sg-buffer
+ */
+unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
+				      unsigned int ofs, unsigned int size)
+{
+	struct snd_sg_buf *sg = dmab->private_data;
+	unsigned int start, end, pg;
+
+	start = ofs >> PAGE_SHIFT;
+	end = (ofs + size - 1) >> PAGE_SHIFT;
+	/* check page continuity */
+	pg = sg->table[start].addr >> PAGE_SHIFT;
+	for (;;) {
+		start++;
+		if (start > end)
+			break;
+		pg++;
+		if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
+			return (start << PAGE_SHIFT) - ofs;
+	}
+	/* ok, all on continuous pages */
+	return size;
+}
+EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 28f3559..6439760 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -27,7 +27,6 @@
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/info.h>
-#include <sound/version.h>
 #include <sound/control.h>
 #include <sound/initval.h>
 #include <linux/kmod.h>
@@ -468,7 +467,7 @@
 	}
 	snd_info_minor_register();
 #ifndef MODULE
-	printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n");
+	printk(KERN_INFO "Advanced Linux Sound Architecture Driver Initialized.\n");
 #endif
 	return 0;
 }
diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c
index 49b9e2409..4b91adc 100644
--- a/sound/drivers/opl4/opl4_synth.c
+++ b/sound/drivers/opl4/opl4_synth.c
@@ -504,8 +504,7 @@
 	spin_lock_irqsave(&opl4->reg_lock, flags);
 	for (i = 0; i < voices; i++) {
 		voice[i] = snd_opl4_get_voice(opl4);
-		list_del(&voice[i]->list);
-		list_add_tail(&voice[i]->list, &opl4->on_voices);
+		list_move_tail(&voice[i]->list, &opl4->on_voices);
 		voice[i]->chan = chan;
 		voice[i]->note = note;
 		voice[i]->velocity = vel & 0x7f;
@@ -555,8 +554,7 @@
 
 static void snd_opl4_voice_off(struct snd_opl4 *opl4, struct opl4_voice *voice)
 {
-	list_del(&voice->list);
-	list_add_tail(&voice->list, &opl4->off_voices);
+	list_move_tail(&voice->list, &opl4->off_voices);
 
 	voice->reg_misc &= ~OPL4_KEY_ON_BIT;
 	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
@@ -571,8 +569,7 @@
 
 static void snd_opl4_terminate_voice(struct snd_opl4 *opl4, struct opl4_voice *voice)
 {
-	list_del(&voice->list);
-	list_add_tail(&voice->list, &opl4->off_voices);
+	list_move_tail(&voice->list, &opl4->off_voices);
 
 	voice->reg_misc = (voice->reg_misc & ~OPL4_KEY_ON_BIT) | OPL4_DAMP_BIT;
 	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 52064cf..a38d964 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -117,6 +117,18 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-azt2320.
 
+config SND_CMI8328
+	tristate "C-Media CMI8328"
+	select SND_WSS_LIB
+	select SND_OPL3_LIB
+	select SND_MPU401_UART
+	help
+	  Say Y here to include support for soundcards based on the
+	  C-Media CMI8328 chip.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-cmi8328.
+
 config SND_CMI8330
 	tristate "C-Media CMI8330"
 	select SND_WSS_LIB
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index 8d781e4..9a15f149 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -6,6 +6,7 @@
 snd-adlib-objs := adlib.o
 snd-als100-objs := als100.o
 snd-azt2320-objs := azt2320.o
+snd-cmi8328-objs := cmi8328.o
 snd-cmi8330-objs := cmi8330.o
 snd-es18xx-objs := es18xx.o
 snd-opl3sa2-objs := opl3sa2.o
@@ -16,6 +17,7 @@
 obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
 obj-$(CONFIG_SND_ALS100) += snd-als100.o
 obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
+obj-$(CONFIG_SND_CMI8328) += snd-cmi8328.o
 obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
 obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 94b83b6..2c2f829 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -63,11 +63,6 @@
 module_param_array(clockfreq, int, NULL, 0444);
 MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).");
 
-struct snd_card_ad1816a {
-	struct pnp_dev *dev;
-	struct pnp_dev *devmpu;
-};
-
 static struct pnp_card_device_id snd_ad1816a_pnpids[] = {
 	/* Analog Devices AD1815 */
 	{ .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } },
@@ -99,25 +94,16 @@
 #define	DRIVER_NAME	"snd-card-ad1816a"
 
 
-static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acard,
-					  struct pnp_card_link *card,
+static int __devinit snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card,
 					  const struct pnp_card_device_id *id)
 {
 	struct pnp_dev *pdev;
 	int err;
 
-	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-	if (acard->dev == NULL)
+	pdev = pnp_request_card_device(card, id->devs[0].id, NULL);
+	if (pdev == NULL)
 		return -EBUSY;
 
-	acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
-	if (acard->devmpu == NULL) {
-		mpu_port[dev] = -1;
-		snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n");
-	}
-
-	pdev = acard->dev;
-
 	err = pnp_activate_dev(pdev);
 	if (err < 0) {
 		printk(KERN_ERR PFX "AUDIO PnP configure failure\n");
@@ -130,16 +116,17 @@
 	dma2[dev] = pnp_dma(pdev, 1);
 	irq[dev] = pnp_irq(pdev, 0);
 
-	if (acard->devmpu == NULL)
+	pdev = pnp_request_card_device(card, id->devs[1].id, NULL);
+	if (pdev == NULL) {
+		mpu_port[dev] = -1;
+		snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n");
 		return 0;
-
-	pdev = acard->devmpu;
+	}
 
 	err = pnp_activate_dev(pdev);
 	if (err < 0) {
 		printk(KERN_ERR PFX "MPU401 PnP configure failure\n");
 		mpu_port[dev] = -1;
-		acard->devmpu = NULL;
 	} else {
 		mpu_port[dev] = pnp_port_start(pdev, 0);
 		mpu_irq[dev] = pnp_irq(pdev, 0);
@@ -153,18 +140,17 @@
 {
 	int error;
 	struct snd_card *card;
-	struct snd_card_ad1816a *acard;
 	struct snd_ad1816a *chip;
 	struct snd_opl3 *opl3;
 	struct snd_timer *timer;
 
 	error = snd_card_create(index[dev], id[dev], THIS_MODULE,
-				sizeof(struct snd_card_ad1816a), &card);
+				sizeof(struct snd_ad1816a), &card);
 	if (error < 0)
 		return error;
-	acard = card->private_data;
+	chip = card->private_data;
 
-	if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
+	if ((error = snd_card_ad1816a_pnp(dev, pcard, pid))) {
 		snd_card_free(card);
 		return error;
 	}
@@ -174,7 +160,7 @@
 					irq[dev],
 					dma1[dev],
 					dma2[dev],
-					&chip)) < 0) {
+					chip)) < 0) {
 		snd_card_free(card);
 		return error;
 	}
@@ -258,13 +244,37 @@
 	pnp_set_card_drvdata(pcard, NULL);
 }
 
+#ifdef CONFIG_PM
+static int snd_ad1816a_pnp_suspend(struct pnp_card_link *pcard,
+				   pm_message_t state)
+{
+	struct snd_card *card = pnp_get_card_drvdata(pcard);
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	snd_ad1816a_suspend(card->private_data);
+	return 0;
+}
+
+static int snd_ad1816a_pnp_resume(struct pnp_card_link *pcard)
+{
+	struct snd_card *card = pnp_get_card_drvdata(pcard);
+
+	snd_ad1816a_resume(card->private_data);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	return 0;
+}
+#endif
+
 static struct pnp_card_driver ad1816a_pnpc_driver = {
 	.flags		= PNP_DRIVER_RES_DISABLE,
 	.name		= "ad1816a",
 	.id_table	= snd_ad1816a_pnpids,
 	.probe		= snd_ad1816a_pnp_detect,
 	.remove		= __devexit_p(snd_ad1816a_pnp_remove),
-	/* FIXME: suspend/resume */
+#ifdef CONFIG_PM
+	.suspend	= snd_ad1816a_pnp_suspend,
+	.resume		= snd_ad1816a_pnp_resume,
+#endif
 };
 
 static int __init alsa_card_ad1816a_init(void)
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 177eed3..db64df6 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -491,7 +491,7 @@
 }
 
 
-static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip)
+static void snd_ad1816a_init(struct snd_ad1816a *chip)
 {
 	unsigned long flags;
 
@@ -511,6 +511,32 @@
 	spin_unlock_irqrestore(&chip->lock, flags);
 }
 
+#ifdef CONFIG_PM
+void snd_ad1816a_suspend(struct snd_ad1816a *chip)
+{
+	int reg;
+	unsigned long flags;
+
+	snd_pcm_suspend_all(chip->pcm);
+	spin_lock_irqsave(&chip->lock, flags);
+	for (reg = 0; reg < 48; reg++)
+		chip->image[reg] = snd_ad1816a_read(chip, reg);
+	spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+void snd_ad1816a_resume(struct snd_ad1816a *chip)
+{
+	int reg;
+	unsigned long flags;
+
+	snd_ad1816a_init(chip);
+	spin_lock_irqsave(&chip->lock, flags);
+	for (reg = 0; reg < 48; reg++)
+		snd_ad1816a_write(chip, reg, chip->image[reg]);
+	spin_unlock_irqrestore(&chip->lock, flags);
+}
+#endif
+
 static int __devinit snd_ad1816a_probe(struct snd_ad1816a *chip)
 {
 	unsigned long flags;
@@ -548,7 +574,6 @@
 		snd_dma_disable(chip->dma2);
 		free_dma(chip->dma2);
 	}
-	kfree(chip);
 	return 0;
 }
 
@@ -573,19 +598,13 @@
 
 int __devinit snd_ad1816a_create(struct snd_card *card,
 				 unsigned long port, int irq, int dma1, int dma2,
-				 struct snd_ad1816a **rchip)
+				 struct snd_ad1816a *chip)
 {
         static struct snd_device_ops ops = {
 		.dev_free =	snd_ad1816a_dev_free,
 	};
 	int error;
-	struct snd_ad1816a *chip;
 
-	*rchip = NULL;
-
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL)
-		return -ENOMEM;
 	chip->irq = -1;
 	chip->dma1 = -1;
 	chip->dma2 = -1;
@@ -631,7 +650,6 @@
 		return error;
 	}
 
-	*rchip = chip;
 	return 0;
 }
 
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
new file mode 100644
index 0000000..bde6013
--- /dev/null
+++ b/sound/isa/cmi8328.c
@@ -0,0 +1,483 @@
+/*
+ * Driver for C-Media CMI8328-based soundcards, such as AudioExcel AV500
+ * Copyright (c) 2012 Ondrej Zary
+ *
+ * AudioExcel AV500 card consists of:
+ *  - CMI8328 - main chip (SB Pro emulation, gameport, OPL3, MPU401, CD-ROM)
+ *  - CS4231A - WSS codec
+ *  - Dream SAM9233+GMS950400+RAM+ROM: Wavetable MIDI, connected to MPU401
+ */
+
+#include <linux/init.h>
+#include <linux/isa.h>
+#include <linux/module.h>
+#include <linux/gameport.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/wss.h>
+#include <sound/opl3.h>
+#include <sound/mpu401.h>
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
+#define SNDRV_LEGACY_FIND_FREE_IRQ
+#define SNDRV_LEGACY_FIND_FREE_DMA
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Ondrej Zary <linux@rainbow-software.org>");
+MODULE_DESCRIPTION("C-Media CMI8328");
+MODULE_LICENSE("GPL");
+
+#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#define SUPPORT_JOYSTICK 1
+#endif
+
+/* I/O port is configured by jumpers on the card to one of these */
+static int cmi8328_ports[] = { 0x530, 0xe80, 0xf40, 0x604 };
+#define CMI8328_MAX	ARRAY_SIZE(cmi8328_ports)
+
+static int index[CMI8328_MAX] =     {[0 ... (CMI8328_MAX-1)] = -1};
+static char *id[CMI8328_MAX] =      {[0 ... (CMI8328_MAX-1)] = NULL};
+static long port[CMI8328_MAX] =     {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT};
+static int irq[CMI8328_MAX] =       {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
+static int dma1[CMI8328_MAX] =      {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
+static int dma2[CMI8328_MAX] =      {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
+static long mpuport[CMI8328_MAX] =  {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT};
+static int mpuirq[CMI8328_MAX] =    {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
+#ifdef SUPPORT_JOYSTICK
+static bool gameport[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = true};
+#endif
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for CMI8328 soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for CMI8328 soundcard.");
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for CMI8328 driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for CMI8328 driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "DMA1 for CMI8328 driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "DMA2 for CMI8328 driver.");
+
+module_param_array(mpuport, long, NULL, 0444);
+MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8328 driver.");
+module_param_array(mpuirq, int, NULL, 0444);
+MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8328 MPU-401 port.");
+#ifdef SUPPORT_JOYSTICK
+module_param_array(gameport, bool, NULL, 0444);
+MODULE_PARM_DESC(gameport, "Enable gameport.");
+#endif
+
+struct snd_cmi8328 {
+	u16 port;
+	u8 cfg[3];
+	u8 wss_cfg;
+	struct snd_card *card;
+	struct snd_wss *wss;
+#ifdef SUPPORT_JOYSTICK
+	struct gameport *gameport;
+#endif
+};
+
+/* CMI8328 configuration registers */
+#define CFG1 0x61
+#define CFG1_SB_DISABLE	(1 << 0)
+#define CFG1_GAMEPORT	(1 << 1)
+/*
+ * bit 0:    SB: 0=enabled, 1=disabled
+ * bit 1:    gameport: 0=disabled, 1=enabled
+ * bits 2-4: SB IRQ: 001=3, 010=5, 011=7, 100=9, 101=10, 110=11
+ * bits 5-6: SB DMA: 00=disabled (when SB disabled), 01=DMA0, 10=DMA1, 11=DMA3
+ * bit 7:    SB port: 0=0x220, 1=0x240
+ */
+#define CFG2 0x62
+#define CFG2_MPU_ENABLE (1 << 2)
+/*
+ * bits 0-1: CD-ROM mode: 00=disabled, 01=Panasonic, 10=Sony/Mitsumi/Wearnes,
+			  11=IDE
+ * bit 2:    MPU401: 0=disabled, 1=enabled
+ * bits 3-4: MPU401 IRQ: 00=3, 01=5, 10=7, 11=9,
+ * bits 5-7: MPU401 port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x332,
+			  101=0x334, 110=0x336
+ */
+#define CFG3 0x63
+/*
+ * bits 0-2: CD-ROM IRQ: 000=disabled, 001=3, 010=5, 011=7, 100=9, 101=10,
+			 110=11
+ * bits 3-4: CD-ROM DMA: 00=disabled, 01=DMA0, 10=DMA1, 11=DMA3
+ * bits 5-7: CD-ROM port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x340,
+			  101=0x350, 110=0x360, 111=0x370
+ */
+
+static u8 snd_cmi8328_cfg_read(u16 port, u8 reg)
+{
+	outb(0x43, port + 3);
+	outb(0x21, port + 3);
+	outb(reg, port + 3);
+	return inb(port);
+}
+
+static void snd_cmi8328_cfg_write(u16 port, u8 reg, u8 val)
+{
+	outb(0x43, port + 3);
+	outb(0x21, port + 3);
+	outb(reg, port + 3);
+	outb(val, port + 3);	/* yes, value goes to the same port as index */
+}
+
+static void snd_cmi8328_cfg_save(u16 port, u8 cfg[])
+{
+	cfg[0] = snd_cmi8328_cfg_read(port, CFG1);
+	cfg[1] = snd_cmi8328_cfg_read(port, CFG2);
+	cfg[2] = snd_cmi8328_cfg_read(port, CFG3);
+}
+
+static void snd_cmi8328_cfg_restore(u16 port, u8 cfg[])
+{
+	snd_cmi8328_cfg_write(port, CFG1, cfg[0]);
+	snd_cmi8328_cfg_write(port, CFG2, cfg[1]);
+	snd_cmi8328_cfg_write(port, CFG3, cfg[2]);
+}
+
+static int __devinit snd_cmi8328_mixer(struct snd_wss *chip)
+{
+	struct snd_card *card;
+	struct snd_ctl_elem_id id1, id2;
+	int err;
+
+	card = chip->card;
+
+	memset(&id1, 0, sizeof(id1));
+	memset(&id2, 0, sizeof(id2));
+	id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	/* rename AUX0 switch to CD */
+	strcpy(id1.name, "Aux Playback Switch");
+	strcpy(id2.name, "CD Playback Switch");
+	err = snd_ctl_rename_id(card, &id1, &id2);
+	if (err < 0) {
+		snd_printk(KERN_ERR "error renaming control\n");
+		return err;
+	}
+	/* rename AUX0 volume to CD */
+	strcpy(id1.name, "Aux Playback Volume");
+	strcpy(id2.name, "CD Playback Volume");
+	err = snd_ctl_rename_id(card, &id1, &id2);
+	if (err < 0) {
+		snd_printk(KERN_ERR "error renaming control\n");
+		return err;
+	}
+	/* rename AUX1 switch to Synth */
+	strcpy(id1.name, "Aux Playback Switch");
+	id1.index = 1;
+	strcpy(id2.name, "Synth Playback Switch");
+	err = snd_ctl_rename_id(card, &id1, &id2);
+	if (err < 0) {
+		snd_printk(KERN_ERR "error renaming control\n");
+		return err;
+	}
+	/* rename AUX1 volume to Synth */
+	strcpy(id1.name, "Aux Playback Volume");
+	id1.index = 1;
+	strcpy(id2.name, "Synth Playback Volume");
+	err = snd_ctl_rename_id(card, &id1, &id2);
+	if (err < 0) {
+		snd_printk(KERN_ERR "error renaming control\n");
+		return err;
+	}
+
+	return 0;
+}
+
+/* find index of an item in "-1"-ended array */
+int array_find(int array[], int item)
+{
+	int i;
+
+	for (i = 0; array[i] != -1; i++)
+		if (array[i] == item)
+			return i;
+
+	return -1;
+}
+/* the same for long */
+int array_find_l(long array[], long item)
+{
+	int i;
+
+	for (i = 0; array[i] != -1; i++)
+		if (array[i] == item)
+			return i;
+
+	return -1;
+}
+
+static int __devinit snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
+{
+	struct snd_card *card;
+	struct snd_opl3 *opl3;
+	struct snd_cmi8328 *cmi;
+#ifdef SUPPORT_JOYSTICK
+	struct resource *res;
+#endif
+	int err, pos;
+	static long mpu_ports[] = { 0x330, 0x300, 0x310, 0x320, 0x332, 0x334,
+				   0x336, -1 };
+	static u8 mpu_port_bits[] = { 3, 0, 1, 2, 4, 5, 6 };
+	static int mpu_irqs[] = { 9, 7, 5, 3, -1 };
+	static u8 mpu_irq_bits[] = { 3, 2, 1, 0 };
+	static int irqs[] = { 9, 10, 11, 7, -1 };
+	static u8 irq_bits[] = { 2, 3, 4, 1 };
+	static int dma1s[] = { 3, 1, 0, -1 };
+	static u8 dma_bits[] = { 3, 2, 1 };
+	static int dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, {0, -1} };
+	u16 port = cmi8328_ports[ndev];
+	u8 val;
+
+	/* 0xff is invalid configuration (but settable - hope it isn't set) */
+	if (snd_cmi8328_cfg_read(port, CFG1) == 0xff)
+		return -ENODEV;
+	/* the SB disable bit must NEVER EVER be cleared or the WSS dies */
+	snd_cmi8328_cfg_write(port, CFG1, CFG1_SB_DISABLE);
+	if (snd_cmi8328_cfg_read(port, CFG1) != CFG1_SB_DISABLE)
+		return -ENODEV;
+	/* disable everything first */
+	snd_cmi8328_cfg_write(port, CFG2, 0);	/* disable CDROM and MPU401 */
+	snd_cmi8328_cfg_write(port, CFG3, 0);	/* disable CDROM IRQ and DMA */
+
+	if (irq[ndev] == SNDRV_AUTO_IRQ) {
+		irq[ndev] = snd_legacy_find_free_irq(irqs);
+		if (irq[ndev] < 0) {
+			snd_printk(KERN_ERR "unable to find a free IRQ\n");
+			return -EBUSY;
+		}
+	}
+	if (dma1[ndev] == SNDRV_AUTO_DMA) {
+		dma1[ndev] = snd_legacy_find_free_dma(dma1s);
+		if (dma1[ndev] < 0) {
+			snd_printk(KERN_ERR "unable to find a free DMA1\n");
+			return -EBUSY;
+		}
+	}
+	if (dma2[ndev] == SNDRV_AUTO_DMA) {
+		dma2[ndev] = snd_legacy_find_free_dma(dma2s[dma1[ndev] % 4]);
+		if (dma2[ndev] < 0) {
+			snd_printk(KERN_WARNING "unable to find a free DMA2, full-duplex will not work\n");
+			dma2[ndev] = -1;
+		}
+	}
+	/* configure WSS IRQ... */
+	pos = array_find(irqs, irq[ndev]);
+	if (pos < 0) {
+		snd_printk(KERN_ERR "invalid IRQ %d\n", irq[ndev]);
+		return -EINVAL;
+	}
+	val = irq_bits[pos] << 3;
+	/* ...and DMA... */
+	pos = array_find(dma1s, dma1[ndev]);
+	if (pos < 0) {
+		snd_printk(KERN_ERR "invalid DMA1 %d\n", dma1[ndev]);
+		return -EINVAL;
+	}
+	val |= dma_bits[pos];
+	/* ...and DMA2 */
+	if (dma2[ndev] >= 0 && dma1[ndev] != dma2[ndev]) {
+		pos = array_find(dma2s[dma1[ndev]], dma2[ndev]);
+		if (pos < 0) {
+			snd_printk(KERN_ERR "invalid DMA2 %d\n", dma2[ndev]);
+			return -EINVAL;
+		}
+		val |= 0x04; /* enable separate capture DMA */
+	}
+	outb(val, port);
+
+	err = snd_card_create(index[ndev], id[ndev], THIS_MODULE,
+				sizeof(struct snd_cmi8328), &card);
+	if (err < 0)
+		return err;
+	cmi = card->private_data;
+	cmi->card = card;
+	cmi->port = port;
+	cmi->wss_cfg = val;
+	snd_card_set_dev(card, pdev);
+
+	err = snd_wss_create(card, port + 4, -1, irq[ndev], dma1[ndev],
+			dma2[ndev], WSS_HW_DETECT, 0, &cmi->wss);
+	if (err < 0)
+		goto error;
+
+	err = snd_wss_pcm(cmi->wss, 0, NULL);
+	if (err < 0)
+		goto error;
+
+	err = snd_wss_mixer(cmi->wss);
+	if (err < 0)
+		goto error;
+	err = snd_cmi8328_mixer(cmi->wss);
+	if (err < 0)
+		goto error;
+
+	if (snd_wss_timer(cmi->wss, 0, NULL) < 0)
+		snd_printk(KERN_WARNING "error initializing WSS timer\n");
+
+	if (mpuport[ndev] == SNDRV_AUTO_PORT) {
+		mpuport[ndev] = snd_legacy_find_free_ioport(mpu_ports, 2);
+		if (mpuport[ndev] < 0)
+			snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
+	}
+	if (mpuirq[ndev] == SNDRV_AUTO_IRQ) {
+		mpuirq[ndev] = snd_legacy_find_free_irq(mpu_irqs);
+		if (mpuirq[ndev] < 0)
+			snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n");
+	}
+	/* enable and configure MPU401 */
+	if (mpuport[ndev] > 0 && mpuirq[ndev] > 0) {
+		val = CFG2_MPU_ENABLE;
+		pos = array_find_l(mpu_ports, mpuport[ndev]);
+		if (pos < 0)
+			snd_printk(KERN_WARNING "invalid MPU401 port 0x%lx\n",
+								mpuport[ndev]);
+		else {
+			val |= mpu_port_bits[pos] << 5;
+			pos = array_find(mpu_irqs, mpuirq[ndev]);
+			if (pos < 0)
+				snd_printk(KERN_WARNING "invalid MPU401 IRQ %d\n",
+								mpuirq[ndev]);
+			else {
+				val |= mpu_irq_bits[pos] << 3;
+				snd_cmi8328_cfg_write(port, CFG2, val);
+				if (snd_mpu401_uart_new(card, 0,
+						MPU401_HW_MPU401, mpuport[ndev],
+						0, mpuirq[ndev], NULL) < 0)
+					snd_printk(KERN_ERR "error initializing MPU401\n");
+			}
+		}
+	}
+	/* OPL3 is hardwired to 0x388 and cannot be disabled */
+	if (snd_opl3_create(card, 0x388, 0x38a, OPL3_HW_AUTO, 0, &opl3) < 0)
+		snd_printk(KERN_ERR "error initializing OPL3\n");
+	else
+		if (snd_opl3_hwdep_new(opl3, 0, 1, NULL) < 0)
+			snd_printk(KERN_WARNING "error initializing OPL3 hwdep\n");
+
+	strcpy(card->driver, "CMI8328");
+	strcpy(card->shortname, "C-Media CMI8328");
+	sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d,%d",
+		card->shortname, cmi->wss->port, irq[ndev], dma1[ndev],
+		(dma2[ndev] >= 0) ? dma2[ndev] : dma1[ndev]);
+
+	dev_set_drvdata(pdev, card);
+	err = snd_card_register(card);
+	if (err < 0)
+		goto error;
+#ifdef SUPPORT_JOYSTICK
+	if (!gameport[ndev])
+		return 0;
+	/* gameport is hardwired to 0x200 */
+	res = request_region(0x200, 8, "CMI8328 gameport");
+	if (!res)
+		snd_printk(KERN_WARNING "unable to allocate gameport I/O port\n");
+	else {
+		struct gameport *gp = cmi->gameport = gameport_allocate_port();
+		if (!cmi->gameport)
+			release_and_free_resource(res);
+		else {
+			gameport_set_name(gp, "CMI8328 Gameport");
+			gameport_set_phys(gp, "%s/gameport0", dev_name(pdev));
+			gameport_set_dev_parent(gp, pdev);
+			gp->io = 0x200;
+			gameport_set_port_data(gp, res);
+			/* Enable gameport */
+			snd_cmi8328_cfg_write(port, CFG1,
+					CFG1_SB_DISABLE | CFG1_GAMEPORT);
+			gameport_register_port(gp);
+		}
+	}
+#endif
+	return 0;
+error:
+	snd_card_free(card);
+
+	return err;
+}
+
+static int __devexit snd_cmi8328_remove(struct device *pdev, unsigned int dev)
+{
+	struct snd_card *card = dev_get_drvdata(pdev);
+	struct snd_cmi8328 *cmi = card->private_data;
+
+#ifdef SUPPORT_JOYSTICK
+	if (cmi->gameport) {
+		struct resource *res = gameport_get_port_data(cmi->gameport);
+		gameport_unregister_port(cmi->gameport);
+		release_and_free_resource(res);
+	}
+#endif
+	/* disable everything */
+	snd_cmi8328_cfg_write(cmi->port, CFG1, CFG1_SB_DISABLE);
+	snd_cmi8328_cfg_write(cmi->port, CFG2, 0);
+	snd_cmi8328_cfg_write(cmi->port, CFG3, 0);
+	snd_card_free(card);
+	dev_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_cmi8328_suspend(struct device *pdev, unsigned int n,
+				pm_message_t state)
+{
+	struct snd_card *card = dev_get_drvdata(pdev);
+	struct snd_cmi8328 *cmi;
+
+	if (!card)	/* ignore absent devices */
+		return 0;
+	cmi = card->private_data;
+	snd_cmi8328_cfg_save(cmi->port, cmi->cfg);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	snd_pcm_suspend_all(cmi->wss->pcm);
+	cmi->wss->suspend(cmi->wss);
+
+	return 0;
+}
+
+static int snd_cmi8328_resume(struct device *pdev, unsigned int n)
+{
+	struct snd_card *card = dev_get_drvdata(pdev);
+	struct snd_cmi8328 *cmi;
+
+	if (!card)	/* ignore absent devices */
+		return 0;
+	cmi = card->private_data;
+	snd_cmi8328_cfg_restore(cmi->port, cmi->cfg);
+	outb(cmi->wss_cfg, cmi->port);
+	cmi->wss->resume(cmi->wss);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+	return 0;
+}
+#endif
+
+static struct isa_driver snd_cmi8328_driver = {
+	.probe		= snd_cmi8328_probe,
+	.remove		= __devexit_p(snd_cmi8328_remove),
+#ifdef CONFIG_PM
+	.suspend	= snd_cmi8328_suspend,
+	.resume		= snd_cmi8328_resume,
+#endif
+	.driver		= {
+		.name	= "cmi8328"
+	},
+};
+
+static int __init alsa_card_cmi8328_init(void)
+{
+	return isa_register_driver(&snd_cmi8328_driver, CMI8328_MAX);
+}
+
+static void __exit alsa_card_cmi8328_exit(void)
+{
+	isa_unregister_driver(&snd_cmi8328_driver);
+}
+
+module_init(alsa_card_cmi8328_init)
+module_exit(alsa_card_cmi8328_exit)
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index a76bc8d..3fc8b66 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -443,9 +443,8 @@
 		for (i = 0; i < 8; ++i)
 			iwave[i] = snd_gf1_peek(gus, bank_pos + i);
 #ifdef CONFIG_SND_DEBUG_ROM
-		printk(KERN_DEBUG "ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos,
-		       iwave[0], iwave[1], iwave[2], iwave[3],
-		       iwave[4], iwave[5], iwave[6], iwave[7]);
+		printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos,
+				  8, iwave);
 #endif
 		if (strncmp(iwave, "INTRWAVE", 8))
 			continue;	/* first check */
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index c24594c..3d1afb6 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -37,6 +37,7 @@
 #include <sound/opl4.h>
 #include <sound/control.h>
 #include <sound/info.h>
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
 #include <sound/initval.h>
@@ -770,20 +771,6 @@
 	return 0;
 }
 
-static long snd_legacy_find_free_ioport(long *port_table, long size)
-{
-	while (*port_table != -1) {
-		struct resource *res;
-		if ((res = request_region(*port_table, size, 
-					  "ALSA test")) != NULL) {
-			release_and_free_resource(res);
-			return *port_table;
-		}
-		port_table++;
-	}
-	return -1;
-}
-
 static int __devinit snd_miro_init(struct snd_miro *chip,
 				   unsigned short hardware)
 {
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index f8fbe22..2899c9f 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -39,6 +39,7 @@
 #ifndef OPTi93X
 #include <sound/opl4.h>
 #endif
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
 #include <sound/initval.h>
@@ -185,19 +186,6 @@
 	"82C930",	"82C931",	"82C933"
 };
 
-
-static long __devinit snd_legacy_find_free_ioport(long *port_table, long size)
-{
-	while (*port_table != -1) {
-		if (request_region(*port_table, size, "ALSA test")) {
-			release_region(*port_table, size);
-			return *port_table;
-		}
-		port_table++;
-	}
-	return -1;
-}
-
 static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
 				      unsigned short hardware)
 {
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index 7188787..2aae6a0 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -417,9 +417,6 @@
 		EMU8000_SMLD_READ(emu); /* discard stale data  */
 		if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
 			break; /* no memory at this address */
-
-		detected_size = size;
-
 		snd_emu8000_read_wait(emu);
 
 		/*
@@ -432,6 +429,18 @@
 		if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
 			break; /* we must have wrapped around */
 		snd_emu8000_read_wait(emu);
+
+		/* Otherwise, it's valid memory. */
+		detected_size = size + 512 * 1024;
+	}
+
+	/* Distinguish 512 KiB from 0. */
+	if (detected_size == 0) {
+		snd_emu8000_read_wait(emu);
+		EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
+		EMU8000_SMLD_READ(emu); /* discard stale data  */
+		if (EMU8000_SMLD_READ(emu) == UNIQUE_ID1)
+			detected_size = 512 * 1024;
 	}
 
 	/* wait until FULL bit in SMAxW register is false */
diff --git a/sound/last.c b/sound/last.c
index 7ffc182..43f2228 100644
--- a/sound/last.c
+++ b/sound/last.c
@@ -19,7 +19,6 @@
  *
  */
 
-#define SNDRV_MAIN_OBJECT_FILE
 #include <linux/init.h>
 #include <sound/core.h>
 
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index a872d0a..66a3bc9 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -2595,6 +2595,21 @@
 			     shared ? 0 : 0x100);
 }
 
+static int alc650_swap_surround_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	struct snd_pcm_chmap *map = ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK];
+
+	if (map) {
+		if (ucontrol->value.integer.value[0])
+			map->chmap = snd_pcm_std_chmaps;
+		else
+			map->chmap = snd_pcm_alt_chmaps;
+	}
+	return snd_ac97_put_volsw(kcontrol, ucontrol);
+}
+
 static const struct snd_kcontrol_new snd_ac97_controls_alc650[] = {
 	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
 	AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0),
@@ -2608,7 +2623,14 @@
 	/* 9: Line-In/Surround share */
 	/* 10: Mic/CLFE share */
 	/* 11-13: in IEC958 controls */
-	AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Swap Surround Slot",
+		.info = snd_ac97_info_volsw,
+		.get = snd_ac97_get_volsw,
+		.put = alc650_swap_surround_put,
+		.private_value =  AC97_SINGLE_VALUE(AC97_ALC650_MULTICH, 14, 1, 0),
+	},
 #if 0 /* always set in patch_alc650 */
 	AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),
 	AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0),
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index ee895f3..c7e3c53 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -270,7 +270,7 @@
 	spinlock_t	reg_lock;
 	spinlock_t	voice_alloc;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	struct snd_ali_image *image;
 #endif
 };
@@ -1883,7 +1883,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ali_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -1989,7 +1989,7 @@
 #define ALI_PM_OPS	&ali_pm
 #else
 #define ALI_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_ali_free(struct snd_ali * codec)
 {
@@ -2000,7 +2000,7 @@
 	if (codec->port)
 		pci_release_regions(codec->pci);
 	pci_disable_device(codec->pci);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	kfree(codec->image);
 #endif
 	pci_dev_put(codec->pci_m1533);
@@ -2232,7 +2232,7 @@
 		return err;
 	}
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);
 	if (!codec->image)
 		snd_printk(KERN_WARNING "can't allocate apm buffer\n");
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 68c4469..00f157a 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -765,7 +765,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_als300_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 0eeca49..feb2a14 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -987,7 +987,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_als4000_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -1040,7 +1040,7 @@
 #define SND_ALS4000_PM_OPS	&snd_als4000_pm
 #else
 #define SND_ALS4000_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver als4000_driver = {
 	.name = KBUILD_MODNAME,
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index e8de831..a51e3ce 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -2968,7 +2968,7 @@
 	.id_table = asihpi_pci_tbl,
 	.probe = snd_asihpi_probe,
 	.remove = __devexit_p(snd_asihpi_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*	.suspend = snd_asihpi_suspend,
 	.resume = snd_asihpi_resume, */
 #endif
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 31020d2..368df8b 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -535,7 +535,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_atiixp_aclink_down(struct atiixp *chip)
 {
 	// if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -1250,6 +1250,7 @@
 static int __devinit snd_atiixp_pcm_new(struct atiixp *chip)
 {
 	struct snd_pcm *pcm;
+	struct snd_pcm_chmap *chmap;
 	struct snd_ac97_bus *pbus = chip->ac97_bus;
 	int err, i, num_pcms;
 
@@ -1293,6 +1294,14 @@
 					      snd_dma_pci_data(chip->pci),
 					      64*1024, 128*1024);
 
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_alt_chmaps, chip->max_channels, 0,
+				     &chmap);
+	if (err < 0)
+		return err;
+	chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+	chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+
 	/* no SPDIF support on codec? */
 	if (chip->pcms[ATI_PCM_SPDIF] && ! chip->pcms[ATI_PCM_SPDIF]->rates)
 		return 0;
@@ -1458,7 +1467,7 @@
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1533,7 +1542,7 @@
 #define SND_ATIIXP_PM_OPS	&snd_atiixp_pm
 #else
 #define SND_ATIIXP_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 
 #ifdef CONFIG_PROC_FS
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 79e204e..6fc03d9 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -511,7 +511,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_atiixp_aclink_down(struct atiixp_modem *chip)
 {
 	// if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -1113,7 +1113,7 @@
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1169,7 +1169,7 @@
 #define SND_ATIIXP_PM_OPS	&snd_atiixp_pm
 #else
 #define SND_ATIIXP_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PROC_FS
 /*
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 4dddd87..c03b66b 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -365,7 +365,7 @@
 	 * CONFIG_PM register storage below, but that's slightly difficult. */
 	u16 shadow_reg_ctrl_6AH;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	/* register value containers for power management
 	 * Note: not always full I/O range preserved (similar to Win driver!) */
 	u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4];
@@ -2729,7 +2729,7 @@
 	snd_azf3328_dbgcallleave();
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static inline void
 snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
 {
@@ -2866,7 +2866,7 @@
 #define SND_AZF3328_PM_OPS	&snd_azf3328_pm
 #else
 #define SND_AZF3328_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver azf3328_driver = {
 	.name = KBUILD_MODNAME,
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index e8e8ccc..04402c1 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -710,7 +710,7 @@
 
 	u16 spi_dac_reg[16];
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 #define NUM_SAVED_VOLUMES	9
 	unsigned int saved_vol[NUM_SAVED_VOLUMES];
 #endif
@@ -733,7 +733,7 @@
 int snd_ca0106_spi_write(struct snd_ca0106 * emu,
 				   unsigned int data);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip);
 void snd_ca0106_mixer_resume(struct snd_ca0106 *chip);
 #else
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 83277b7..65c5591 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1334,10 +1334,29 @@
 	return IRQ_HANDLED;
 }
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ }
+};
+
+static const struct snd_pcm_chmap_elem clfe_map[] = {
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+	{ }
+};
+
+static const struct snd_pcm_chmap_elem side_map[] = {
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+	{ }
+};
+
 static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
 {
 	struct snd_pcm *pcm;
 	struct snd_pcm_substream *substream;
+	const struct snd_pcm_chmap_elem *map = NULL;
 	int err;
   
 	err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm);
@@ -1350,18 +1369,22 @@
 	case 0:
 	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_front_ops);
 	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_0_ops);
+	  map = snd_pcm_std_chmaps;
           break;
 	case 1:
 	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_rear_ops);
 	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_1_ops);
+	  map = surround_map;
           break;
 	case 2:
 	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_center_lfe_ops);
 	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_2_ops);
+	  map = clfe_map;
           break;
 	case 3:
 	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_unknown_ops);
 	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_3_ops);
+	  map = side_map;
           break;
         }
 
@@ -1388,6 +1411,11 @@
 			return err;
 	}
   
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
+				     1 << 2, NULL);
+	if (err < 0)
+		return err;
+
 	emu->pcm[device] = pcm;
   
 	return 0;
@@ -1871,7 +1899,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_ca0106_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 84f3f92..68eacf7 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -907,7 +907,7 @@
         return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 struct ca0106_vol_tbl {
 	unsigned int channel_id;
 	unsigned int reg;
@@ -953,4 +953,4 @@
 	if (chip->details->i2c_adc)
 		ca0106_set_capture_mic_line_in(chip);
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index b7d6f2b..22122ff 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -504,7 +504,7 @@
 
 	spinlock_t reg_lock;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	unsigned int saved_regs[0x20];
 	unsigned char saved_mixers[0x20];
 #endif
@@ -1962,6 +1962,12 @@
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(cm->pci), 64*1024, 128*1024);
 
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_alt_chmaps, cm->max_channels, 0,
+				     NULL);
+	if (err < 0)
+		return err;
+
 	return 0;
 }
 
@@ -3315,7 +3321,7 @@
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -3403,7 +3409,7 @@
 #define SND_CMIPCI_PM_OPS	&snd_cmipci_pm
 #else
 #define SND_CMIPCI_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver cmipci_driver = {
 	.name = KBUILD_MODNAME,
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 45a83170..8e86ec0 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -486,7 +486,7 @@
 
 	struct gameport *gameport;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	u32 suspend_regs[SUSPEND_REGISTERS];
 #endif
 
@@ -1977,7 +1977,7 @@
 /*
  * Power Management
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int saved_regs[SUSPEND_REGISTERS] = {
 	BA0_JSCTL,
@@ -2089,7 +2089,7 @@
 #define CS4281_PM_OPS	&cs4281_pm
 #else
 #define CS4281_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver cs4281_driver = {
 	.name = KBUILD_MODNAME,
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 1e007c7..575bed0 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -166,7 +166,7 @@
 	.id_table = snd_cs46xx_ids,
 	.probe = snd_card_cs46xx_probe,
 	.remove = __devexit_p(snd_card_cs46xx_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	.driver = {
 		.pm = &snd_cs46xx_pm,
 	},
diff --git a/sound/pci/cs46xx/cs46xx.h b/sound/pci/cs46xx/cs46xx.h
index 29d8a8d..fc339ef 100644
--- a/sound/pci/cs46xx/cs46xx.h
+++ b/sound/pci/cs46xx/cs46xx.h
@@ -1721,7 +1721,7 @@
 	unsigned int play_ctl;
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	u32 *saved_regs;
 #endif
 };
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index a71d1c14..a2bb8c9 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2797,7 +2797,7 @@
 	}
 #endif
 	
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	kfree(chip->saved_regs);
 #endif
 
@@ -3590,7 +3590,7 @@
 /*
  * APM support
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static unsigned int saved_regs[] = {
 	BA0_ACOSV,
 	/*BA0_ASER_FADDR,*/
@@ -3711,7 +3711,7 @@
 }
 
 SIMPLE_DEV_PM_OPS(snd_cs46xx_pm, snd_cs46xx_suspend, snd_cs46xx_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 
 /*
@@ -3868,7 +3868,7 @@
 	
 	snd_cs46xx_proc_init(card, chip);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *
 				   ARRAY_SIZE(saved_regs), GFP_KERNEL);
 	if (!chip->saved_regs) {
diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h
index b518949..86f1462 100644
--- a/sound/pci/cs46xx/cs46xx_lib.h
+++ b/sound/pci/cs46xx/cs46xx_lib.h
@@ -90,7 +90,7 @@
 struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);
 void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int cs46xx_dsp_resume(struct snd_cs46xx * chip);
 #endif
 struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name,
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 56fec0b..1686b4f 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -287,7 +287,7 @@
 		if (ins->scbs[i].deleted) continue;
 
 		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 		kfree(ins->scbs[i].data);
 #endif
 	}
@@ -1019,7 +1019,7 @@
 {
 	struct dsp_scb_descriptor * desc;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	/* copy the data for resume */
 	scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
 	if (!scb_data)
@@ -1032,7 +1032,7 @@
 		_dsp_create_scb(chip,scb_data,dest);
 	} else {
 		snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 		kfree(scb_data);
 #endif
 	}
@@ -1937,7 +1937,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int cs46xx_dsp_resume(struct snd_cs46xx * chip)
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index c2c695b..409e876 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -203,7 +203,7 @@
 	remove_symbol (chip,scb->scb_symbol);
 
 	ins->scbs[scb->index].deleted = 1;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	kfree(ins->scbs[scb->index].data);
 	ins->scbs[scb->index].data = NULL;
 #endif
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index f1e4229..d1cca28 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -142,8 +142,7 @@
 
 	mem = pci_ioremap_bar(pci, 0);
 	if (mem == NULL) {
-		kfree(chip);
-		pci_disable_device(pci);
+		snd_cs5530_free(chip);
 		return -EBUSY;
 	}
 
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile
index ccc6422..a8f75f8 100644
--- a/sound/pci/cs5535audio/Makefile
+++ b/sound/pci/cs5535audio/Makefile
@@ -3,7 +3,7 @@
 #
 
 snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
-snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
+snd-cs5535audio-$(CONFIG_PM_SLEEP) += cs5535audio_pm.o
 snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o
 
 # Toplevel Module Dependency
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 51f64ba..4915efa 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -399,7 +399,7 @@
 	.id_table = snd_cs5535audio_ids,
 	.probe = snd_cs5535audio_probe,
 	.remove = __devexit_p(snd_cs5535audio_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	.driver = {
 		.pm = &snd_cs5535audio_pm,
 	},
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 2f6e9c7..a2f997a 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -1536,7 +1536,7 @@
 	}
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atc_suspend(struct ct_atc *atc)
 {
 	int i;
@@ -1647,7 +1647,7 @@
 	.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
+#ifdef CONFIG_PM_SLEEP
 	.suspend = atc_suspend,
 	.resume = atc_resume,
 #endif
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
index 653e813..69b51f9 100644
--- a/sound/pci/ctxfi/ctatc.h
+++ b/sound/pci/ctxfi/ctatc.h
@@ -143,7 +143,7 @@
 
 	struct ct_timer *timer;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	int (*suspend)(struct ct_atc *atc);
 	int (*resume)(struct ct_atc *atc);
 #define NUM_PCMS (NUM_CTALSADEVS - 1)
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index c56fe53..5977e9a 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -72,7 +72,7 @@
 	int (*card_init)(struct hw *hw, struct card_conf *info);
 	int (*card_stop)(struct hw *hw);
 	int (*pll_init)(struct hw *hw, unsigned int rsr);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	int (*suspend)(struct hw *hw);
 	int (*resume)(struct hw *hw, struct card_conf *info);
 #endif
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index dc1969b..4507f70 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -2085,7 +2085,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int hw_suspend(struct hw *hw)
 {
 	struct pci_dev *pci = hw->pci;
@@ -2180,7 +2180,7 @@
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
 	.capabilities = hw_capabilities,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	.suspend = hw_suspend,
 	.resume = hw_resume,
 #endif
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 9d1231d..b9c9349 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -2201,7 +2201,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int hw_suspend(struct hw *hw)
 {
 	struct pci_dev *pci = hw->pci;
@@ -2250,7 +2250,7 @@
 	.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
+#ifdef CONFIG_PM_SLEEP
 	.suspend = hw_suspend,
 	.resume = hw_resume,
 #endif
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index 0cc13ee..48fe0e3 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -1118,7 +1118,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int mixer_resume(struct ct_mixer *mixer)
 {
 	int i, state;
@@ -1188,7 +1188,7 @@
 	mixer->get_output_ports = mixer_get_output_ports;
 	mixer->set_input_left = mixer_set_input_left;
 	mixer->set_input_right = mixer_set_input_right;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	mixer->resume = mixer_resume;
 #endif
 
diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h
index b009e98..be881c6 100644
--- a/sound/pci/ctxfi/ctmixer.h
+++ b/sound/pci/ctxfi/ctmixer.h
@@ -56,7 +56,7 @@
 			      enum MIXER_PORT_T type, struct rsc *rsc);
 	int (*set_input_right)(struct ct_mixer *mixer,
 			       enum MIXER_PORT_T type, struct rsc *rsc);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	int (*resume)(struct ct_mixer *mixer);
 #endif
 };
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
index 2c86226..e8a4feb 100644
--- a/sound/pci/ctxfi/ctpcm.c
+++ b/sound/pci/ctxfi/ctpcm.c
@@ -395,12 +395,38 @@
 	.page		= snd_pcm_sgbuf_ops_page,
 };
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+	{ .channels = 1,
+	  .map = { SNDRV_CHMAP_MONO } },
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ }
+};
+
+static const struct snd_pcm_chmap_elem clfe_map[] = {
+	{ .channels = 1,
+	  .map = { SNDRV_CHMAP_MONO } },
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+	{ }
+};
+
+static const struct snd_pcm_chmap_elem side_map[] = {
+	{ .channels = 1,
+	  .map = { SNDRV_CHMAP_MONO } },
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+	{ }
+};
+
 /* Create ALSA pcm device */
 int ct_alsa_pcm_create(struct ct_atc *atc,
 		       enum CTALSADEVS device,
 		       const char *device_name)
 {
 	struct snd_pcm *pcm;
+	const struct snd_pcm_chmap_elem *map;
+	int chs;
 	int err;
 	int playback_count, capture_count;
 
@@ -427,7 +453,31 @@
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 			snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
 
-#ifdef CONFIG_PM
+	chs = 2;
+	switch (device) {
+	case FRONT:
+		chs = 8;
+		map = snd_pcm_std_chmaps;
+		break;
+	case SURROUND:
+		map = surround_map;
+		break;
+	case CLFE:
+		map = clfe_map;
+		break;
+	case SIDE:
+		map = side_map;
+		break;
+	default:
+		map = snd_pcm_std_chmaps;
+		break;
+	}
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, chs,
+				     0, NULL);
+	if (err < 0)
+		return err;
+
+#ifdef CONFIG_PM_SLEEP
 	atc->pcms[device] = pcm;
 #endif
 
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
index e002183..07c07d7 100644
--- a/sound/pci/ctxfi/xfi.c
+++ b/sound/pci/ctxfi/xfi.c
@@ -125,7 +125,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ct_card_suspend(struct device *dev)
 {
 	struct snd_card *card = dev_get_drvdata(dev);
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 0ff754f..abb0b86 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -46,7 +46,7 @@
 	int err;
 	char name[30];
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	if (chip->fw_cache[fw_index]) {
 		DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
 		*fw_entry = chip->fw_cache[fw_index];
@@ -59,7 +59,7 @@
 	err = request_firmware(fw_entry, name, pci_device(chip));
 	if (err < 0)
 		snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	else
 		chip->fw_cache[fw_index] = *fw_entry;
 #endif
@@ -70,7 +70,7 @@
 
 static void free_firmware(const struct firmware *fw_entry)
 {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	DE_ACT(("firmware not released (kept in cache)\n"));
 #else
 	release_firmware(fw_entry);
@@ -82,7 +82,7 @@
 
 static void free_firmware_cache(struct echoaudio *chip)
 {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	int i;
 
 	for (i = 0; i < 8 ; i++)
@@ -2203,7 +2203,7 @@
 
 
 
-#if defined(CONFIG_PM)
+#if defined(CONFIG_PM_SLEEP)
 
 static int snd_echo_suspend(struct device *dev)
 {
@@ -2313,7 +2313,7 @@
 #define SND_ECHO_PM_OPS	&snd_echo_pm
 #else
 #define SND_ECHO_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 
 static void __devexit snd_echo_remove(struct pci_dev *pci)
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h
index 1df974d..e158369 100644
--- a/sound/pci/echoaudio/echoaudio.h
+++ b/sound/pci/echoaudio/echoaudio.h
@@ -449,7 +449,7 @@
 	volatile u32 __iomem *dsp_registers;	/* DSP's register base */
 	u32 active_mask;			/* Chs. active mask or
 						 * punks out */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	const struct firmware *fw_cache[8];	/* Cached firmwares */
 #endif
 
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index ddac4e6..b7c1875 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -206,7 +206,7 @@
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_emu10k1_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -268,7 +268,7 @@
 #define SND_EMU10K1_PM_OPS	&snd_emu10k1_pm
 #else
 #define SND_EMU10K1_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver emu10k1_driver = {
 	.name = KBUILD_MODNAME,
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 7549240..bed4485 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1241,7 +1241,7 @@
  *  Create the EMU10K1 instance
  */
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int alloc_pm_buffer(struct snd_emu10k1 *emu);
 static void free_pm_buffer(struct snd_emu10k1 *emu);
 #endif
@@ -1275,7 +1275,7 @@
 		snd_dma_free_pages(&emu->ptb_pages);
 	vfree(emu->page_ptr_table);
 	vfree(emu->page_addr_table);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	free_pm_buffer(emu);
 #endif
 	if (emu->port)
@@ -1971,7 +1971,7 @@
 	err = snd_emu10k1_init(emu, enable_ir, 0);
 	if (err < 0)
 		goto error;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	err = alloc_pm_buffer(emu);
 	if (err < 0)
 		goto error;
@@ -2000,7 +2000,7 @@
 	return err;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static unsigned char saved_regs[] = {
 	CPF, PTRX, CVCF, VTFT, Z1, Z2, PSST, DSL, CCCA, CCR, CLP,
 	FXRT, MAPA, MAPB, ENVVOL, ATKHLDV, DCYSUSV, LFOVAL1, ENVVAL,
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 5c8978b..556fd6f 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -830,9 +830,22 @@
 	return IRQ_HANDLED;
 }
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ }
+};
+
+static const struct snd_pcm_chmap_elem clfe_map[] = {
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+	{ }
+};
+
 static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm)
 {
 	struct snd_pcm *pcm;
+	const struct snd_pcm_chmap_elem *map = NULL;
 	int err;
 	int capture = 0;
   
@@ -861,12 +874,15 @@
 	switch(device) {
 	case 0:
 		strcpy(pcm->name, "EMU10K1X Front");
+		map = snd_pcm_std_chmaps;
 		break;
 	case 1:
 		strcpy(pcm->name, "EMU10K1X Rear");
+		map = surround_map;
 		break;
 	case 2:
 		strcpy(pcm->name, "EMU10K1X Center/LFE");
+		map = clfe_map;
 		break;
 	}
 	emu->pcm = pcm;
@@ -875,6 +891,11 @@
 					      snd_dma_pci_data(emu->pci), 
 					      32*1024, 32*1024);
   
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
+				     1 << 2, NULL);
+	if (err < 0)
+		return err;
+
 	if (rpcm)
 		*rpcm = pcm;
   
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index dae4050..5241995 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -2646,7 +2646,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
 {
 	int len;
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index 0a43662..ae709c1 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -263,8 +263,8 @@
 	spin_lock_irqsave(&emu->memblk_lock, flags);
 	if (blk->mapped_page >= 0) {
 		/* update order link */
-		list_del(&blk->mapped_order_link);
-		list_add_tail(&blk->mapped_order_link, &emu->mapped_order_link_head);
+		list_move_tail(&blk->mapped_order_link,
+			       &emu->mapped_order_link_head);
 		spin_unlock_irqrestore(&emu->memblk_lock, flags);
 		return 0;
 	}
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index a81dc44..88cec6b 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -893,7 +893,7 @@
         return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 #define NUM_CHS	1	/* up to 4, but only first channel is used */
 
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index f7e6f73..5674cc3 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -55,8 +55,10 @@
 
 #ifdef CHIP1370
 #define DRIVER_NAME "ENS1370"
+#define CHIP_NAME "ES1370" /* it can be ENS but just to keep compatibility... */
 #else
 #define DRIVER_NAME "ENS1371"
+#define CHIP_NAME "ES1371"
 #endif
 
 
@@ -1258,6 +1260,14 @@
 	.pointer =	snd_ensoniq_capture_pointer,
 };
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+	{ .channels = 1,
+	  .map = { SNDRV_CHMAP_MONO } },
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ }
+};
+
 static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,
 				     struct snd_pcm ** rpcm)
 {
@@ -1266,11 +1276,7 @@
 
 	if (rpcm)
 		*rpcm = NULL;
-#ifdef CHIP1370
-	err = snd_pcm_new(ensoniq->card, "ES1370/1", device, 1, 1, &pcm);
-#else
-	err = snd_pcm_new(ensoniq->card, "ES1371/1", device, 1, 1, &pcm);
-#endif
+	err = snd_pcm_new(ensoniq->card, CHIP_NAME "/1", device, 1, 1, &pcm);
 	if (err < 0)
 		return err;
 
@@ -1283,16 +1289,22 @@
 
 	pcm->private_data = ensoniq;
 	pcm->info_flags = 0;
-#ifdef CHIP1370
-	strcpy(pcm->name, "ES1370 DAC2/ADC");
-#else
-	strcpy(pcm->name, "ES1371 DAC2/ADC");
-#endif
+	strcpy(pcm->name, CHIP_NAME " DAC2/ADC");
 	ensoniq->pcm1 = pcm;
 
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
 
+#ifdef CHIP1370
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     surround_map, 2, 0, NULL);
+#else
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_std_chmaps, 2, 0, NULL);
+#endif
+	if (err < 0)
+		return err;
+
 	if (rpcm)
 		*rpcm = pcm;
 	return 0;
@@ -1306,11 +1318,7 @@
 
 	if (rpcm)
 		*rpcm = NULL;
-#ifdef CHIP1370
-	err = snd_pcm_new(ensoniq->card, "ES1370/2", device, 1, 0, &pcm);
-#else
-	err = snd_pcm_new(ensoniq->card, "ES1371/2", device, 1, 0, &pcm);
-#endif
+	err = snd_pcm_new(ensoniq->card, CHIP_NAME "/2", device, 1, 0, &pcm);
 	if (err < 0)
 		return err;
 
@@ -1321,16 +1329,22 @@
 #endif
 	pcm->private_data = ensoniq;
 	pcm->info_flags = 0;
-#ifdef CHIP1370
-	strcpy(pcm->name, "ES1370 DAC1");
-#else
-	strcpy(pcm->name, "ES1371 DAC1");
-#endif
+	strcpy(pcm->name, CHIP_NAME " DAC1");
 	ensoniq->pcm2 = pcm;
 
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
 
+#ifdef CHIP1370
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_std_chmaps, 2, 0, NULL);
+#else
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     surround_map, 2, 0, NULL);
+#endif
+	if (err < 0)
+		return err;
+
 	if (rpcm)
 		*rpcm = pcm;
 	return 0;
@@ -1885,11 +1899,7 @@
 {
 	struct ensoniq *ensoniq = entry->private_data;
 
-#ifdef CHIP1370
-	snd_iprintf(buffer, "Ensoniq AudioPCI ES1370\n\n");
-#else
-	snd_iprintf(buffer, "Ensoniq AudioPCI ES1371\n\n");
-#endif
+	snd_iprintf(buffer, "Ensoniq AudioPCI " CHIP_NAME "\n\n");
 	snd_iprintf(buffer, "Joystick enable  : %s\n",
 		    ensoniq->ctrl & ES_JYSTK_EN ? "on" : "off");
 #ifdef CHIP1370
@@ -2032,7 +2042,7 @@
 	synchronize_irq(ensoniq->irq);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_ensoniq_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -2094,7 +2104,7 @@
 #define SND_ENSONIQ_PM_OPS	&snd_ensoniq_pm
 #else
 #define SND_ENSONIQ_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int __devinit snd_ensoniq_create(struct snd_card *card,
 				     struct pci_dev *pci,
@@ -2361,11 +2371,7 @@
 		*rrawmidi = NULL;
 	if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0)
 		return err;
-#ifdef CHIP1370
-	strcpy(rmidi->name, "ES1370");
-#else
-	strcpy(rmidi->name, "ES1371");
-#endif
+	strcpy(rmidi->name, CHIP_NAME);
 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_ensoniq_midi_output);
 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_ensoniq_midi_input);
 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT |
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index dbb8180..394c5d4 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -236,7 +236,7 @@
 #ifdef SUPPORT_JOYSTICK
 	struct gameport *gameport;
 #endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	unsigned char saved_regs[SAVED_REG_SIZE];
 #endif
 };
@@ -1456,7 +1456,7 @@
 	outb(0, SLDM_REG(chip, DMACLEAR));
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * PM support
  */
@@ -1536,7 +1536,7 @@
 #define ES1938_PM_OPS	&es1938_pm
 #else
 #define ES1938_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef SUPPORT_JOYSTICK
 static int __devinit snd_es1938_create_gameport(struct es1938 *chip)
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index fb4c90b9..5d0e568 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -491,7 +491,7 @@
 	/* linked list */
 	struct list_head list;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	u16 wc_map[4];
 #endif
 };
@@ -544,7 +544,7 @@
 	struct list_head substream_list;
 	spinlock_t substream_lock;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	u16 apu_map[NR_APUS][NR_APU_REGS];
 #endif
 
@@ -706,7 +706,7 @@
 {
 	if (snd_BUG_ON(channel >= NR_APUS))
 		return;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	chip->apu_map[channel][reg] = data;
 #endif
 	reg |= (channel << 4);
@@ -993,7 +993,7 @@
 	/* set the wavecache control reg */
 	wave_set_register(chip, es->apu[channel] << 3, tmpval);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	es->wc_map[channel] = tmpval;
 #endif
 }
@@ -2377,7 +2377,7 @@
 	outw(w, chip->io_port + ESM_PORT_HOST_IRQ);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * PM support
  */
@@ -2461,7 +2461,7 @@
 #define ES1968_PM_OPS	&es1968_pm
 #else
 #define ES1968_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef SUPPORT_JOYSTICK
 #define JOYSTICK_ADDR	0x200
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 522c870..cc2e91d 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -205,7 +205,7 @@
 	struct snd_tea575x tea;
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	u16 saved_regs[0x20];
 #endif
 };
@@ -711,6 +711,13 @@
 					      snd_dma_pci_data(chip->pci),
 					      chip->multichannel ? 128*1024 : 64*1024, 128*1024);
 
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_alt_chmaps,
+				     chip->multichannel ? 6 : 2, 0,
+				     NULL);
+	if (err < 0)
+		return err;
+
 	if (rpcm)
 		*rpcm = pcm;
 	return 0;
@@ -1361,7 +1368,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static unsigned char saved_regs[] = {
 	FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC,
 	FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2,
@@ -1421,7 +1428,7 @@
 #define SND_FM801_PM_OPS	&snd_fm801_pm
 #else
 #define SND_FM801_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver fm801_driver = {
 	.name = KBUILD_MODNAME,
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 194d625..7105c3d 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -228,17 +228,9 @@
 	  Say Y here to enable the generic HD-audio codec parser
 	  in snd-hda-intel driver.
 
-config SND_HDA_POWER_SAVE
-	bool "Aggressive power-saving on HD-audio"
-	depends on PM
-	help
-	  Say Y here to enable more aggressive power-saving mode on
-	  HD-audio driver.  The power-saving timeout can be configured
-	  via power_save option or over sysfs on-the-fly.
-
 config SND_HDA_POWER_SAVE_DEFAULT
 	int "Default time-out for HD-audio power-save mode"
-	depends on SND_HDA_POWER_SAVE
+	depends on PM
 	default 0
 	help
 	  The default time-out value in seconds for HD-audio automatic
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 4f7d2df..a98e25eb 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -141,7 +141,6 @@
 	memset(sequences_hp, 0, sizeof(sequences_hp));
 	assoc_line_out = 0;
 
-	codec->ignore_misc_bit = true;
 	end_nid = codec->start_nid + codec->num_nodes;
 	for (nid = codec->start_nid; nid < end_nid; nid++) {
 		unsigned int wid_caps = get_wcaps(codec, nid);
@@ -157,9 +156,6 @@
 			continue;
 
 		def_conf = snd_hda_codec_get_pincfg(codec, nid);
-		if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
-		      AC_DEFCFG_MISC_NO_PRESENCE))
-			codec->ignore_misc_bit = false;
 		conn = get_defcfg_connect(def_conf);
 		if (conn == AC_JACK_PORT_NONE)
 			continue;
@@ -739,7 +735,8 @@
 		for (q = quirk; q->subvendor; q++) {
 			unsigned int vendorid =
 				q->subdevice | (q->subvendor << 16);
-			if (vendorid == codec->subsystem_id) {
+			unsigned int mask = 0xffff0000 | q->subdevice_mask;
+			if ((codec->subsystem_id & mask) == (vendorid & mask)) {
 				id = q->value;
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 				name = q->name;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 1c65cc5e..960800b 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -94,13 +94,19 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static void hda_power_work(struct work_struct *work);
 static void hda_keep_power_on(struct hda_codec *codec);
 #define hda_codec_is_power_on(codec)	((codec)->power_on)
+static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up)
+{
+	if (bus->ops.pm_notify)
+		bus->ops.pm_notify(bus, power_up);
+}
 #else
 static inline void hda_keep_power_on(struct hda_codec *codec) {}
 #define hda_codec_is_power_on(codec)	1
+#define hda_call_pm_notify(bus, state) {}
 #endif
 
 /**
@@ -808,7 +814,7 @@
 {
 	struct hda_codec_preset_list *tbl;
 	const struct hda_codec_preset *preset;
-	int mod_requested = 0;
+	unsigned int mod_requested = 0;
 
 	if (is_generic_config(codec))
 		return NULL; /* use the generic parser */
@@ -1186,7 +1192,7 @@
 		return;
 	snd_hda_jack_tbl_clear(codec);
 	restore_init_pincfgs(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	cancel_delayed_work(&codec->power_work);
 	flush_workqueue(codec->bus->workq);
 #endif
@@ -1199,6 +1205,10 @@
 	codec->bus->caddr_tbl[codec->addr] = NULL;
 	if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
+#ifdef CONFIG_PM
+	if (!codec->pm_down_notified) /* cancel leftover refcounts */
+		hda_call_pm_notify(codec->bus, false);
+#endif
 	module_put(codec->owner);
 	free_hda_cache(&codec->amp_cache);
 	free_hda_cache(&codec->cmd_cache);
@@ -1212,7 +1222,7 @@
 static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
 				hda_nid_t fg, unsigned int power_state);
 
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+static unsigned int hda_set_power_state(struct hda_codec *codec,
 				unsigned int power_state);
 
 /**
@@ -1229,6 +1239,7 @@
 {
 	struct hda_codec *codec;
 	char component[31];
+	hda_nid_t fg;
 	int err;
 
 	if (snd_BUG_ON(!bus))
@@ -1263,7 +1274,7 @@
 	snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
 	snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	spin_lock_init(&codec->power_lock);
 	INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
 	/* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
@@ -1271,6 +1282,7 @@
 	 * phase.
 	 */
 	hda_keep_power_on(codec);
+	hda_call_pm_notify(bus, true);
 #endif
 
 	if (codec->bus->modelname) {
@@ -1304,7 +1316,8 @@
 		goto error;
 	}
 
-	err = read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg);
+	fg = codec->afg ? codec->afg : codec->mfg;
+	err = read_widget_caps(codec, fg);
 	if (err < 0) {
 		snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
 		goto error;
@@ -1314,20 +1327,22 @@
 		goto error;
 
 	if (!codec->subsystem_id) {
-		hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;
 		codec->subsystem_id =
-			snd_hda_codec_read(codec, nid, 0,
+			snd_hda_codec_read(codec, fg, 0,
 					   AC_VERB_GET_SUBSYSTEM_ID, 0);
 	}
 
-	codec->epss = snd_hda_codec_get_supported_ps(codec,
-					codec->afg ? codec->afg : codec->mfg,
+#ifdef CONFIG_PM
+	codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg,
+					AC_PWRST_CLKSTOP);
+	if (!codec->d3_stop_clk)
+		bus->power_keep_link_on = 1;
+#endif
+	codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
 					AC_PWRST_EPSS);
 
 	/* power-up all before initialization */
-	hda_set_power_state(codec,
-			    codec->afg ? codec->afg : codec->mfg,
-			    AC_PWRST_D0);
+	hda_set_power_state(codec, AC_PWRST_D0);
 
 	snd_hda_codec_proc_new(codec);
 
@@ -2335,7 +2350,7 @@
 
 	/* OK, let it free */
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	cancel_delayed_work_sync(&codec->power_work);
 	codec->power_on = 0;
 	codec->power_transition = 0;
@@ -3500,20 +3515,6 @@
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
 				    power_state);
 	}
-
-	if (power_state == AC_PWRST_D0) {
-		unsigned long end_time;
-		int state;
-		/* wait until the codec reachs to D0 */
-		end_time = jiffies + msecs_to_jiffies(500);
-		do {
-			state = snd_hda_codec_read(codec, fg, 0,
-						   AC_VERB_GET_POWER_STATE, 0);
-			if (state == power_state)
-				break;
-			msleep(1);
-		} while (time_after_eq(end_time, jiffies));
-	}
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
 
@@ -3534,19 +3535,41 @@
 }
 
 /*
- * set power state of the codec
+ * wait until the state is reached, returns the current state
  */
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
-				unsigned int power_state)
+static unsigned int hda_sync_power_state(struct hda_codec *codec,
+					 hda_nid_t fg,
+					 unsigned int power_state)
 {
+	unsigned long end_time = jiffies + msecs_to_jiffies(500);
+	unsigned int state, actual_state;
+
+	for (;;) {
+		state = snd_hda_codec_read(codec, fg, 0,
+					   AC_VERB_GET_POWER_STATE, 0);
+		if (state & AC_PWRST_ERROR)
+			break;
+		actual_state = (state >> 4) & 0x0f;
+		if (actual_state == power_state)
+			break;
+		if (time_after_eq(jiffies, end_time))
+			break;
+		/* wait until the codec reachs to the target state */
+		msleep(1);
+	}
+	return state;
+}
+
+/*
+ * set power state of the codec, and return the power state
+ */
+static unsigned int hda_set_power_state(struct hda_codec *codec,
+					unsigned int power_state)
+{
+	hda_nid_t fg = codec->afg ? codec->afg : codec->mfg;
 	int count;
 	unsigned int state;
 
-	if (codec->patch_ops.set_power_state) {
-		codec->patch_ops.set_power_state(codec, fg, power_state);
-		return;
-	}
-
 	/* this delay seems necessary to avoid click noise at power-down */
 	if (power_state == AC_PWRST_D3) {
 		/* transition time less than 10ms for power down */
@@ -3555,14 +3578,22 @@
 
 	/* repeat power states setting at most 10 times*/
 	for (count = 0; count < 10; count++) {
-		snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
-				    power_state);
-		snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
-		state = snd_hda_codec_read(codec, fg, 0,
-					   AC_VERB_GET_POWER_STATE, 0);
+		if (codec->patch_ops.set_power_state)
+			codec->patch_ops.set_power_state(codec, fg,
+							 power_state);
+		else {
+			snd_hda_codec_read(codec, fg, 0,
+					   AC_VERB_SET_POWER_STATE,
+					   power_state);
+			snd_hda_codec_set_power_to_all(codec, fg, power_state,
+						       true);
+		}
+		state = hda_sync_power_state(codec, fg, power_state);
 		if (!(state & AC_PWRST_ERROR))
 			break;
 	}
+
+	return state;
 }
 
 #ifdef CONFIG_SND_HDA_HWDEP
@@ -3579,16 +3610,16 @@
 #ifdef CONFIG_PM
 /*
  * call suspend and power-down; used both from PM and power-save
+ * this function returns the power state in the end
  */
-static void hda_call_codec_suspend(struct hda_codec *codec)
+static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
 {
+	unsigned int state;
+
 	if (codec->patch_ops.suspend)
 		codec->patch_ops.suspend(codec);
 	hda_cleanup_all_streams(codec);
-	hda_set_power_state(codec,
-			    codec->afg ? codec->afg : codec->mfg,
-			    AC_PWRST_D3);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+	state = hda_set_power_state(codec, AC_PWRST_D3);
 	cancel_delayed_work(&codec->power_work);
 	spin_lock(&codec->power_lock);
 	snd_hda_update_power_acct(codec);
@@ -3597,7 +3628,7 @@
 	codec->power_transition = 0;
 	codec->power_jiffies = jiffies;
 	spin_unlock(&codec->power_lock);
-#endif
+	return state;
 }
 
 /*
@@ -3609,9 +3640,7 @@
 	 * in the resume / power-save sequence
 	 */
 	hda_keep_power_on(codec);
-	hda_set_power_state(codec,
-			    codec->afg ? codec->afg : codec->mfg,
-			    AC_PWRST_D0);
+	hda_set_power_state(codec, AC_PWRST_D0);
 	restore_pincfgs(codec); /* restore all current pin configs */
 	restore_shutup_pins(codec);
 	hda_exec_init_verbs(codec);
@@ -3624,6 +3653,7 @@
 		snd_hda_codec_resume_amp(codec);
 		snd_hda_codec_resume_cache(codec);
 	}
+	snd_hda_jack_report_sync(codec);
 	snd_hda_power_down(codec); /* flag down before returning */
 }
 #endif /* CONFIG_PM */
@@ -3658,6 +3688,36 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_build_controls);
 
+/*
+ * add standard channel maps if not specified
+ */
+static int add_std_chmaps(struct hda_codec *codec)
+{
+	int i, str, err;
+
+	for (i = 0; i < codec->num_pcms; i++) {
+		for (str = 0; str < 2; str++) {
+			struct snd_pcm *pcm = codec->pcm_info[i].pcm;
+			struct hda_pcm_stream *hinfo =
+				&codec->pcm_info[i].stream[str];
+			struct snd_pcm_chmap *chmap;
+
+			if (codec->pcm_info[i].own_chmap)
+				continue;
+			if (!pcm || !hinfo->substreams)
+				continue;
+			err = snd_pcm_add_chmap_ctls(pcm, str,
+						     snd_pcm_std_chmaps,
+						     hinfo->channels_max,
+						     0, &chmap);
+			if (err < 0)
+				return err;
+			chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+		}
+	}
+	return 0;
+}
+
 int snd_hda_codec_build_controls(struct hda_codec *codec)
 {
 	int err = 0;
@@ -3669,6 +3729,13 @@
 		err = codec->patch_ops.build_controls(codec);
 	if (err < 0)
 		return err;
+
+	/* we create chmaps here instead of build_pcms */
+	err = add_std_chmaps(codec);
+	if (err < 0)
+		return err;
+
+	snd_hda_jack_report_sync(codec); /* call at the last init point */
 	return 0;
 }
 
@@ -4211,7 +4278,7 @@
  *
  * This function returns 0 if successful, or a negative error code.
  */
-int __devinit snd_hda_build_pcms(struct hda_bus *bus)
+int snd_hda_build_pcms(struct hda_bus *bus)
 {
 	struct hda_codec *codec;
 
@@ -4391,12 +4458,13 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static void hda_power_work(struct work_struct *work)
 {
 	struct hda_codec *codec =
 		container_of(work, struct hda_codec, power_work.work);
 	struct hda_bus *bus = codec->bus;
+	unsigned int state;
 
 	spin_lock(&codec->power_lock);
 	if (codec->power_transition > 0) { /* during power-up sequence? */
@@ -4410,9 +4478,12 @@
 	}
 	spin_unlock(&codec->power_lock);
 
-	hda_call_codec_suspend(codec);
-	if (bus->ops.pm_notify)
-		bus->ops.pm_notify(bus);
+	state = hda_call_codec_suspend(codec);
+	codec->pm_down_notified = 0;
+	if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) {
+		codec->pm_down_notified = 1;
+		hda_call_pm_notify(bus, false);
+	}
 }
 
 static void hda_keep_power_on(struct hda_codec *codec)
@@ -4438,19 +4509,16 @@
 /* Transition to powered up, if wait_power_down then wait for a pending
  * transition to D3 to complete. A pending D3 transition is indicated
  * with power_transition == -1. */
+/* call this with codec->power_lock held! */
 static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
 {
 	struct hda_bus *bus = codec->bus;
 
-	spin_lock(&codec->power_lock);
-	codec->power_count++;
 	/* Return if power_on or transitioning to power_on, unless currently
 	 * powering down. */
 	if ((codec->power_on || codec->power_transition > 0) &&
-	    !(wait_power_down && codec->power_transition < 0)) {
-		spin_unlock(&codec->power_lock);
+	    !(wait_power_down && codec->power_transition < 0))
 		return;
-	}
 	spin_unlock(&codec->power_lock);
 
 	cancel_delayed_work_sync(&codec->power_work);
@@ -4462,9 +4530,9 @@
 	if (codec->power_on) {
 		if (codec->power_transition < 0)
 			codec->power_transition = 0;
-		spin_unlock(&codec->power_lock);
 		return;
 	}
+
 	trace_hda_power_up(codec);
 	snd_hda_update_power_acct(codec);
 	codec->power_on = 1;
@@ -4472,71 +4540,54 @@
 	codec->power_transition = 1; /* avoid reentrance */
 	spin_unlock(&codec->power_lock);
 
-	if (bus->ops.pm_notify)
-		bus->ops.pm_notify(bus);
+	if (codec->pm_down_notified) {
+		codec->pm_down_notified = 0;
+		hda_call_pm_notify(bus, true);
+	}
+
 	hda_call_codec_resume(codec);
 
 	spin_lock(&codec->power_lock);
 	codec->power_transition = 0;
-	spin_unlock(&codec->power_lock);
 }
 
-/**
- * snd_hda_power_up - Power-up the codec
- * @codec: HD-audio codec
- *
- * Increment the power-up counter and power up the hardware really when
- * not turned on yet.
- */
-void snd_hda_power_up(struct hda_codec *codec)
-{
-	__snd_hda_power_up(codec, false);
-}
-EXPORT_SYMBOL_HDA(snd_hda_power_up);
-
-/**
- * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
- *   D3 transition to complete.  This differs from snd_hda_power_up() when
- *   power_transition == -1.  snd_hda_power_up sees this case as a nop,
- *   snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
- *   back up.
- * @codec: HD-audio codec
- *
- * Cancel any power down operation hapenning on the work queue, then power up.
- */
-void snd_hda_power_up_d3wait(struct hda_codec *codec)
-{
-	/* This will cancel and wait for pending power_work to complete. */
-	__snd_hda_power_up(codec, true);
-}
-EXPORT_SYMBOL_HDA(snd_hda_power_up_d3wait);
-
 #define power_save(codec)	\
 	((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
 
-/**
- * snd_hda_power_down - Power-down the codec
- * @codec: HD-audio codec
- *
- * Decrement the power-up counter and schedules the power-off work if
- * the counter rearches to zero.
- */
-void snd_hda_power_down(struct hda_codec *codec)
+/* Transition to powered down */
+static void __snd_hda_power_down(struct hda_codec *codec)
 {
-	spin_lock(&codec->power_lock);
-	--codec->power_count;
-	if (!codec->power_on || codec->power_count || codec->power_transition) {
-		spin_unlock(&codec->power_lock);
+	if (!codec->power_on || codec->power_count || codec->power_transition)
 		return;
-	}
+
 	if (power_save(codec)) {
 		codec->power_transition = -1; /* avoid reentrance */
 		queue_delayed_work(codec->bus->workq, &codec->power_work,
 				msecs_to_jiffies(power_save(codec) * 1000));
 	}
+}
+
+/**
+ * snd_hda_power_save - Power-up/down/sync the codec
+ * @codec: HD-audio codec
+ * @delta: the counter delta to change
+ *
+ * Change the power-up counter via @delta, and power up or down the hardware
+ * appropriately.  For the power-down, queue to the delayed action.
+ * Passing zero to @delta means to synchronize the power state.
+ */
+void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait)
+{
+	spin_lock(&codec->power_lock);
+	codec->power_count += delta;
+	trace_hda_power_count(codec);
+	if (delta > 0)
+		__snd_hda_power_up(codec, d3wait);
+	else
+		__snd_hda_power_down(codec);
 	spin_unlock(&codec->power_lock);
 }
-EXPORT_SYMBOL_HDA(snd_hda_power_down);
+EXPORT_SYMBOL_HDA(snd_hda_power_save);
 
 /**
  * snd_hda_check_amp_list_power - Check the amp list and update the power
@@ -5087,9 +5138,6 @@
  * @bus: the HDA bus
  *
  * Returns 0 if successful.
- *
- * This function is defined only when POWER_SAVE isn't set.
- * In the power-save mode, the codec is resumed dynamically.
  */
 int snd_hda_resume(struct hda_bus *bus)
 {
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index e5a7e19..507fe8a 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -386,6 +386,10 @@
 /* DIGITAL2 bits */
 #define AC_DIG2_CC			(0x7f<<0)
 
+/* DIGITAL3 bits */
+#define AC_DIG3_ICT			(0xf<<0)
+#define AC_DIG3_KAE			(1<<7)
+
 /* Pin widget control - 8bit */
 #define AC_PINCTL_EPT			(0x3<<0)
 #define AC_PINCTL_EPT_NATIVE		0
@@ -610,9 +614,9 @@
 			  struct hda_pcm *pcm);
 	/* reset bus for retry verb */
 	void (*bus_reset)(struct hda_bus *bus);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	/* notify power-up/down from codec to controller */
-	void (*pm_notify)(struct hda_bus *bus);
+	void (*pm_notify)(struct hda_bus *bus, bool power_up);
 #endif
 };
 
@@ -708,8 +712,6 @@
 #ifdef CONFIG_PM
 	int (*suspend)(struct hda_codec *codec);
 	int (*resume)(struct hda_codec *codec);
-#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
 	int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);
 #endif
 	void (*reboot_notify)(struct hda_codec *codec);
@@ -774,6 +776,7 @@
 	unsigned int pcm_type;	/* HDA_PCM_TYPE_XXX */
 	int device;		/* device number to assign */
 	struct snd_pcm *pcm;	/* assigned PCM instance */
+	bool own_chmap;		/* codec driver provides own channel maps */
 };
 
 /* codec information */
@@ -859,12 +862,13 @@
 	unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
 	unsigned int pins_shutup:1;	/* pins are shut up */
 	unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
-	unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */
 	unsigned int no_jack_detect:1;	/* Machine has no jack-detection */
 	unsigned int pcm_format_first:1; /* PCM format must be set first */
 	unsigned int epss:1;		/* supporting EPSS? */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	unsigned int power_on :1;	/* current (global) power-state */
+	unsigned int d3_stop_clk:1;	/* support D3 operation without BCLK */
+	unsigned int pm_down_notified:1; /* PM notified to controller */
 	int power_transition;	/* power-state in transition */
 	int power_count;	/* current (global) power refcount */
 	struct delayed_work power_work; /* delayed task for powerdown */
@@ -1042,7 +1046,7 @@
 static inline
 int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	if (codec->patch_ops.check_power_status)
 		return codec->patch_ops.check_power_status(codec, nid);
 #endif
@@ -1059,22 +1063,70 @@
 /*
  * power saving
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-void snd_hda_power_up(struct hda_codec *codec);
-void snd_hda_power_up_d3wait(struct hda_codec *codec);
-void snd_hda_power_down(struct hda_codec *codec);
+#ifdef CONFIG_PM
+void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait);
 void snd_hda_update_power_acct(struct hda_codec *codec);
 #else
-static inline void snd_hda_power_up(struct hda_codec *codec) {}
-static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) {}
-static inline void snd_hda_power_down(struct hda_codec *codec) {}
+static inline void snd_hda_power_save(struct hda_codec *codec, int delta,
+				      bool d3wait) {}
 #endif
 
+/**
+ * snd_hda_power_up - Power-up the codec
+ * @codec: HD-audio codec
+ *
+ * Increment the power-up counter and power up the hardware really when
+ * not turned on yet.
+ */
+static inline void snd_hda_power_up(struct hda_codec *codec)
+{
+	snd_hda_power_save(codec, 1, false);
+}
+
+/**
+ * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
+ *   D3 transition to complete.  This differs from snd_hda_power_up() when
+ *   power_transition == -1.  snd_hda_power_up sees this case as a nop,
+ *   snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
+ *   back up.
+ * @codec: HD-audio codec
+ *
+ * Cancel any power down operation hapenning on the work queue, then power up.
+ */
+static inline void snd_hda_power_up_d3wait(struct hda_codec *codec)
+{
+	snd_hda_power_save(codec, 1, true);
+}
+
+/**
+ * snd_hda_power_down - Power-down the codec
+ * @codec: HD-audio codec
+ *
+ * Decrement the power-up counter and schedules the power-off work if
+ * the counter rearches to zero.
+ */
+static inline void snd_hda_power_down(struct hda_codec *codec)
+{
+	snd_hda_power_save(codec, -1, false);
+}
+
+/**
+ * snd_hda_power_sync - Synchronize the power-save status
+ * @codec: HD-audio codec
+ *
+ * Synchronize the actual power state with the power account;
+ * called when power_save parameter is changed
+ */
+static inline void snd_hda_power_sync(struct hda_codec *codec)
+{
+	snd_hda_power_save(codec, 0, false);
+}
+
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 /*
  * patch firmware
  */
-int snd_hda_load_patch(struct hda_bus *bus, const char *patch);
+int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);
 #endif
 
 /*
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 431bf86..b81d3d0 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -70,7 +70,7 @@
 
 	struct list_head nid_list;	/* list of widgets */
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 #define MAX_LOOPBACK_AMPS	7
 	struct hda_loopback_check loopback;
 	int num_loopbacks;
@@ -654,7 +654,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid,
 			       int dir, int idx)
 {
@@ -1028,7 +1028,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct hda_gspec *spec = codec->spec;
@@ -1043,7 +1043,7 @@
 	.build_controls = build_generic_controls,
 	.build_pcms = build_generic_pcms,
 	.free = snd_hda_generic_free,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	.check_power_status = generic_check_power_status,
 #endif
 };
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 6b2efb8..1af86d4 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -25,7 +25,6 @@
 #include <linux/mutex.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
-#include <linux/firmware.h>
 #include <linux/export.h>
 #include <sound/core.h>
 #include "hda_codec.h"
@@ -156,7 +155,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static ssize_t power_on_acct_show(struct device *dev,
 				  struct device_attribute *attr,
 				  char *buf)
@@ -192,7 +191,7 @@
 					  hwdep->device, &power_attrs[i]);
 	return 0;
 }
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
+#endif /* CONFIG_PM */
 
 #ifdef CONFIG_SND_HDA_RECONFIG
 
@@ -747,18 +746,21 @@
  *
  * the spaces at the beginning and the end of the line are stripped
  */
-static int get_line_from_fw(char *buf, int size, struct firmware *fw)
+static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
+			    const void **fw_data_p)
 {
 	int len;
-	const char *p = fw->data;
-	while (isspace(*p) && fw->size) {
+	size_t fw_size = *fw_size_p;
+	const char *p = *fw_data_p;
+
+	while (isspace(*p) && fw_size) {
 		p++;
-		fw->size--;
+		fw_size--;
 	}
-	if (!fw->size)
+	if (!fw_size)
 		return 0;
 
-	for (len = 0; len < fw->size; len++) {
+	for (len = 0; len < fw_size; len++) {
 		if (!*p)
 			break;
 		if (*p == '\n') {
@@ -770,8 +772,8 @@
 			*buf++ = *p++;
 	}
 	*buf = 0;
-	fw->size -= len;
-	fw->data = p;
+	*fw_size_p = fw_size - len;
+	*fw_data_p = p;
 	remove_trail_spaces(buf);
 	return 1;
 }
@@ -779,29 +781,15 @@
 /*
  * load a "patch" firmware file and parse it
  */
-int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
+int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
 {
-	int err;
-	const struct firmware *fw;
-	struct firmware tmp;
 	char buf[128];
 	struct hda_codec *codec;
 	int line_mode;
-	struct device *dev = bus->card->dev;
 
-	if (snd_BUG_ON(!dev))
-		return -ENODEV;
-	err = request_firmware(&fw, patch, dev);
-	if (err < 0) {
-		printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n",
-		       patch);
-		return err;
-	}
-
-	tmp = *fw;
 	line_mode = LINE_MODE_NONE;
 	codec = NULL;
-	while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) {
+	while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
 		if (!*buf || *buf == '#' || *buf == '\n')
 			continue;
 		if (*buf == '[')
@@ -810,7 +798,6 @@
 			 (codec || !patch_items[line_mode].need_codec))
 			patch_items[line_mode].parser(buf, bus, &codec);
 	}
-	release_firmware(fw);
 	return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_load_patch);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c4763c5..f09ff6c 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -46,6 +46,7 @@
 #include <linux/mutex.h>
 #include <linux/reboot.h>
 #include <linux/io.h>
+#include <linux/pm_runtime.h>
 #ifdef CONFIG_X86
 /* for snoop control */
 #include <asm/pgtable.h>
@@ -55,6 +56,7 @@
 #include <sound/initval.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
+#include <linux/firmware.h>
 #include "hda_codec.h"
 
 
@@ -62,7 +64,7 @@
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 static char *model[SNDRV_CARDS];
-static int position_fix[SNDRV_CARDS];
+static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_only[SNDRV_CARDS];
@@ -86,7 +88,7 @@
 MODULE_PARM_DESC(model, "Use the given board model.");
 module_param_array(position_fix, int, NULL, 0444);
 MODULE_PARM_DESC(position_fix, "DMA pointer read method."
-		 "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
+		 "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
@@ -108,9 +110,16 @@
 			    "(0=off, 1=on) (default=1).");
 #endif
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
+static int param_set_xint(const char *val, const struct kernel_param *kp);
+static struct kernel_param_ops param_ops_xint = {
+	.set = param_set_xint,
+	.get = param_get_int,
+};
+#define param_check_xint param_check_int
+
 static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
-module_param(power_save, int, 0644);
+module_param(power_save, xint, 0644);
 MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
 		 "(in second, 0 = disable).");
 
@@ -121,7 +130,7 @@
 static bool power_save_controller = 1;
 module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
-#endif
+#endif /* CONFIG_PM */
 
 static int align_buffer_size = -1;
 module_param(align_buffer_size, bint, 0644);
@@ -406,6 +415,7 @@
 	 */
 	unsigned int insufficient :1;
 	unsigned int wc_marked:1;
+	unsigned int no_period_wakeup:1;
 };
 
 /* CORB/RIRB */
@@ -471,6 +481,10 @@
 	struct snd_dma_buffer rb;
 	struct snd_dma_buffer posbuf;
 
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+	const struct firmware *fw;
+#endif
+
 	/* flags */
 	int position_fix[2]; /* for both playback/capture streams */
 	int poll_count;
@@ -498,6 +512,9 @@
 
 	/* reboot notifier (for mysterious hangup problem at power-down) */
 	struct notifier_block reboot_notifier;
+
+	/* card list (for power_save trigger) */
+	struct list_head list;
 };
 
 /* driver types */
@@ -538,6 +555,7 @@
 #define AZX_DCAPS_ALIGN_BUFSIZE	(1 << 22)	/* buffer size alignment */
 #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)	/* BDLE in 4k boundary */
 #define AZX_DCAPS_POSFIX_COMBO  (1 << 24)	/* Use COMBO as default */
+#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)	/* Take LPIB as delay */
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -560,13 +578,17 @@
  * VGA-switcher support
  */
 #ifdef SUPPORT_VGA_SWITCHEROO
+#define use_vga_switcheroo(chip)	((chip)->use_vga_switcheroo)
+#else
+#define use_vga_switcheroo(chip)	0
+#endif
+
+#if defined(SUPPORT_VGA_SWITCHEROO) || defined(CONFIG_SND_HDA_PATCH_LOADER)
 #define DELAYED_INIT_MARK
 #define DELAYED_INITDATA_MARK
-#define use_vga_switcheroo(chip)	((chip)->use_vga_switcheroo)
 #else
 #define DELAYED_INIT_MARK	__devinit
 #define DELAYED_INITDATA_MARK	__devinitdata
-#define use_vga_switcheroo(chip)	0
 #endif
 
 static char *driver_short_names[] DELAYED_INITDATA_MARK = {
@@ -1012,8 +1034,8 @@
 		return azx_rirb_get_response(bus, addr);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static void azx_power_notify(struct hda_bus *bus);
+#ifdef CONFIG_PM
+static void azx_power_notify(struct hda_bus *bus, bool power_up);
 #endif
 
 /* reset codec link */
@@ -1269,6 +1291,11 @@
 	u8 sd_status;
 	int i, ok;
 
+#ifdef CONFIG_PM_RUNTIME
+	if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
+		return IRQ_NONE;
+#endif
+
 	spin_lock(&chip->reg_lock);
 
 	if (chip->disabled) {
@@ -1394,7 +1421,7 @@
 	ofs = 0;
 	azx_dev->frags = 0;
 	pos_adj = bdl_pos_adj[chip->dev_index];
-	if (pos_adj > 0) {
+	if (!azx_dev->no_period_wakeup && pos_adj > 0) {
 		struct snd_pcm_runtime *runtime = substream->runtime;
 		int pos_align = pos_adj;
 		pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
@@ -1410,8 +1437,7 @@
 			pos_adj = 0;
 		} else {
 			ofs = setup_bdle(chip, substream, azx_dev,
-					 &bdl, ofs, pos_adj,
-					 !substream->runtime->no_period_wakeup);
+					 &bdl, ofs, pos_adj, true);
 			if (ofs < 0)
 				goto error;
 		}
@@ -1424,7 +1450,7 @@
 		else
 			ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
 					 period_bytes,
-					 !substream->runtime->no_period_wakeup);
+					 !azx_dev->no_period_wakeup);
 		if (ofs < 0)
 			goto error;
 	}
@@ -1580,7 +1606,7 @@
 	bus_temp.ops.get_response = azx_get_response;
 	bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
 	bus_temp.ops.bus_reset = azx_bus_reset;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	bus_temp.power_save = &power_save;
 	bus_temp.ops.pm_notify = azx_power_notify;
 #endif
@@ -1897,10 +1923,12 @@
 
 	if (bufsize != azx_dev->bufsize ||
 	    period_bytes != azx_dev->period_bytes ||
-	    format_val != azx_dev->format_val) {
+	    format_val != azx_dev->format_val ||
+	    runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
 		azx_dev->bufsize = bufsize;
 		azx_dev->period_bytes = period_bytes;
 		azx_dev->format_val = format_val;
+		azx_dev->no_period_wakeup = runtime->no_period_wakeup;
 		err = azx_setup_periods(chip, substream, azx_dev);
 		if (err < 0)
 			return err;
@@ -1959,14 +1987,14 @@
 	}
 
 	spin_lock(&chip->reg_lock);
-	if (nsync > 1) {
-		/* first, set SYNC bits of corresponding streams */
-		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);
-	}
+
+	/* first, set SYNC bits of corresponding streams */
+	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)
 			continue;
@@ -1984,8 +2012,6 @@
 	}
 	spin_unlock(&chip->reg_lock);
 	if (start) {
-		if (nsync == 1)
-			return 0;
 		/* wait until all FIFOs get ready */
 		for (timeout = 5000; timeout; timeout--) {
 			nwait = 0;
@@ -2018,16 +2044,14 @@
 			cpu_relax();
 		}
 	}
-	if (nsync > 1) {
-		spin_lock(&chip->reg_lock);
-		/* reset SYNC bits */
-		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);
-	}
+	spin_lock(&chip->reg_lock);
+	/* reset SYNC bits */
+	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;
 }
 
@@ -2120,6 +2144,27 @@
 
 	if (pos >= azx_dev->bufsize)
 		pos = 0;
+
+	/* calculate runtime delay from LPIB */
+	if (azx_dev->substream->runtime &&
+	    chip->position_fix[stream] == POS_FIX_POSBUF &&
+	    (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
+		unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB);
+		int delay;
+		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+			delay = pos - lpib_pos;
+		else
+			delay = lpib_pos - pos;
+		if (delay < 0)
+			delay += azx_dev->bufsize;
+		if (delay >= azx_dev->period_bytes) {
+			snd_printdd("delay %d > period_bytes %d\n",
+				delay, azx_dev->period_bytes);
+			delay = 0; /* something is wrong */
+		}
+		azx_dev->substream->runtime->delay =
+			bytes_to_frames(azx_dev->substream->runtime, delay);
+	}
 	return pos;
 }
 
@@ -2379,33 +2424,65 @@
 	chip->initialized = 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 /* power-up/down the controller */
-static void azx_power_notify(struct hda_bus *bus)
+static void azx_power_notify(struct hda_bus *bus, bool power_up)
 {
 	struct azx *chip = bus->private_data;
-	struct hda_codec *c;
-	int power_on = 0;
 
-	list_for_each_entry(c, &bus->codec_list, list) {
-		if (c->power_on) {
-			power_on = 1;
-			break;
-		}
-	}
-	if (power_on)
-		azx_init_chip(chip, 1);
-	else if (chip->running && power_save_controller &&
-		 !bus->power_keep_link_on)
-		azx_stop_chip(chip);
+	if (power_up)
+		pm_runtime_get_sync(&chip->pci->dev);
+	else
+		pm_runtime_put_sync(&chip->pci->dev);
 }
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
 
-#ifdef CONFIG_PM
+static DEFINE_MUTEX(card_list_lock);
+static LIST_HEAD(card_list);
+
+static void azx_add_card_list(struct azx *chip)
+{
+	mutex_lock(&card_list_lock);
+	list_add(&chip->list, &card_list);
+	mutex_unlock(&card_list_lock);
+}
+
+static void azx_del_card_list(struct azx *chip)
+{
+	mutex_lock(&card_list_lock);
+	list_del_init(&chip->list);
+	mutex_unlock(&card_list_lock);
+}
+
+/* trigger power-save check at writing parameter */
+static int param_set_xint(const char *val, const struct kernel_param *kp)
+{
+	struct azx *chip;
+	struct hda_codec *c;
+	int prev = power_save;
+	int ret = param_set_int(val, kp);
+
+	if (ret || prev == power_save)
+		return ret;
+
+	mutex_lock(&card_list_lock);
+	list_for_each_entry(chip, &card_list, list) {
+		if (!chip->bus || chip->disabled)
+			continue;
+		list_for_each_entry(c, &chip->bus->codec_list, list)
+			snd_hda_power_sync(c);
+	}
+	mutex_unlock(&card_list_lock);
+	return 0;
+}
+#else
+#define azx_add_card_list(chip) /* NOP */
+#define azx_del_card_list(chip) /* NOP */
+#endif /* CONFIG_PM */
+
+#if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO)
 /*
  * power management
  */
-
 static int azx_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -2460,11 +2537,41 @@
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	return 0;
 }
-static SIMPLE_DEV_PM_OPS(azx_pm, azx_suspend, azx_resume);
+#endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */
+
+#ifdef CONFIG_PM_RUNTIME
+static int azx_runtime_suspend(struct device *dev)
+{
+	struct snd_card *card = dev_get_drvdata(dev);
+	struct azx *chip = card->private_data;
+
+	if (!power_save_controller)
+		return -EAGAIN;
+
+	azx_stop_chip(chip);
+	azx_clear_irq_pending(chip);
+	return 0;
+}
+
+static int azx_runtime_resume(struct device *dev)
+{
+	struct snd_card *card = dev_get_drvdata(dev);
+	struct azx *chip = card->private_data;
+
+	azx_init_pci(chip);
+	azx_init_chip(chip, 1);
+	return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops azx_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
+	SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, NULL)
+};
+
 #define AZX_PM_OPS	&azx_pm
 #else
-#define azx_suspend(dev)
-#define azx_resume(dev)
 #define AZX_PM_OPS	NULL
 #endif /* CONFIG_PM */
 
@@ -2599,6 +2706,8 @@
 {
 	int i;
 
+	azx_del_card_list(chip);
+
 	azx_notifier_unregister(chip);
 
 	if (use_vga_switcheroo(chip)) {
@@ -2640,6 +2749,10 @@
 		pci_release_regions(chip->pci);
 	pci_disable_device(chip->pci);
 	kfree(chip->azx_dev);
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+	if (chip->fw)
+		release_firmware(chip->fw);
+#endif
 	kfree(chip);
 
 	return 0;
@@ -2719,6 +2832,7 @@
 	const struct snd_pci_quirk *q;
 
 	switch (fix) {
+	case POS_FIX_AUTO:
 	case POS_FIX_LPIB:
 	case POS_FIX_POSBUF:
 	case POS_FIX_VIACOMBO:
@@ -2904,6 +3018,7 @@
 	chip->dev_index = dev;
 	INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
 	INIT_LIST_HEAD(&chip->pcm_list);
+	INIT_LIST_HEAD(&chip->list);
 	init_vga_switcheroo(chip);
 
 	chip->position_fix[0] = chip->position_fix[1] =
@@ -3138,7 +3253,7 @@
 
 static void power_down_all_codecs(struct azx *chip)
 {
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	/* The codecs were powered up in snd_hda_codec_new().
 	 * Now all initialization done, so turn them down if possible
 	 */
@@ -3149,12 +3264,40 @@
 #endif
 }
 
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+/* callback from request_firmware_nowait() */
+static void azx_firmware_cb(const struct firmware *fw, void *context)
+{
+	struct snd_card *card = context;
+	struct azx *chip = card->private_data;
+	struct pci_dev *pci = chip->pci;
+
+	if (!fw) {
+		snd_printk(KERN_ERR SFX "Cannot load firmware, aborting\n");
+		goto error;
+	}
+
+	chip->fw = fw;
+	if (!chip->disabled) {
+		/* continue probing */
+		if (azx_probe_continue(chip))
+			goto error;
+	}
+	return; /* OK */
+
+ error:
+	snd_card_free(card);
+	pci_set_drvdata(pci, NULL);
+}
+#endif
+
 static int __devinit azx_probe(struct pci_dev *pci,
 			       const struct pci_device_id *pci_id)
 {
 	static int dev;
 	struct snd_card *card;
 	struct azx *chip;
+	bool probe_now;
 	int err;
 
 	if (dev >= SNDRV_CARDS)
@@ -3170,15 +3313,28 @@
 		return err;
 	}
 
-	/* set this here since it's referred in snd_hda_load_patch() */
 	snd_card_set_dev(card, &pci->dev);
 
 	err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
 	if (err < 0)
 		goto out_free;
 	card->private_data = chip;
+	probe_now = !chip->disabled;
 
-	if (!chip->disabled) {
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+	if (patch[dev] && *patch[dev]) {
+		snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
+			   patch[dev]);
+		err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
+					      &pci->dev, GFP_KERNEL, card,
+					      azx_firmware_cb);
+		if (err < 0)
+			goto out_free;
+		probe_now = false; /* continued in azx_firmware_cb() */
+	}
+#endif /* CONFIG_SND_HDA_PATCH_LOADER */
+
+	if (probe_now) {
 		err = azx_probe_continue(chip);
 		if (err < 0)
 			goto out_free;
@@ -3186,6 +3342,9 @@
 
 	pci_set_drvdata(pci, card);
 
+	if (pci_dev_run_wake(pci))
+		pm_runtime_put_noidle(&pci->dev);
+
 	dev++;
 	return 0;
 
@@ -3208,12 +3367,13 @@
 	if (err < 0)
 		goto out_free;
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
-	if (patch[dev] && *patch[dev]) {
-		snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
-			   patch[dev]);
-		err = snd_hda_load_patch(chip->bus, patch[dev]);
+	if (chip->fw) {
+		err = snd_hda_load_patch(chip->bus, chip->fw->size,
+					 chip->fw->data);
 		if (err < 0)
 			goto out_free;
+		release_firmware(chip->fw); /* no longer needed */
+		chip->fw = NULL;
 	}
 #endif
 	if ((probe_only[dev] & 1) == 0) {
@@ -3239,6 +3399,7 @@
 	chip->running = 1;
 	power_down_all_codecs(chip);
 	azx_notifier_register(chip);
+	azx_add_card_list(chip);
 
 	return 0;
 
@@ -3250,6 +3411,10 @@
 static void __devexit azx_remove(struct pci_dev *pci)
 {
 	struct snd_card *card = pci_get_drvdata(pci);
+
+	if (pci_dev_run_wake(pci))
+		pm_runtime_get_noresume(&pci->dev);
+
 	if (card)
 		snd_card_free(card);
 	pci_set_drvdata(pci, NULL);
@@ -3260,7 +3425,7 @@
 	/* CPT */
 	{ PCI_DEVICE(0x8086, 0x1c20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
 	/* PBG */
 	{ PCI_DEVICE(0x8086, 0x1d20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
@@ -3268,23 +3433,30 @@
 	/* Panther Point */
 	{ PCI_DEVICE(0x8086, 0x1e20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
 	/* Lynx Point */
 	{ PCI_DEVICE(0x8086, 0x8c20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
 	/* Lynx Point-LP */
 	{ PCI_DEVICE(0x8086, 0x9c20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
 	/* Lynx Point-LP */
 	{ PCI_DEVICE(0x8086, 0x9c21),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
 	/* Haswell */
 	{ PCI_DEVICE(0x8086, 0x0c0c),
 	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
-	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+	{ PCI_DEVICE(0x8086, 0x0d0c),
+	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+	/* 5 Series/3400 */
+	{ PCI_DEVICE(0x8086, 0x3b56),
+	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
+	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
 	/* SCH */
 	{ PCI_DEVICE(0x8086, 0x811b),
 	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index aaccc02..c9333c9 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -26,9 +26,8 @@
 		return false;
 	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
 		return false;
-	if (!codec->ignore_misc_bit &&
-	    (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
-	     AC_DEFCFG_MISC_NO_PRESENCE))
+	if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+	     AC_DEFCFG_MISC_NO_PRESENCE)
 		return false;
 	if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
 		return false;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 1b4c129..09dbdc3 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -529,7 +529,7 @@
 static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
 #endif
 
-#if defined(CONFIG_SND_HDA_POWER_SAVE) && defined(CONFIG_SND_HDA_HWDEP)
+#if defined(CONFIG_PM) && defined(CONFIG_SND_HDA_HWDEP)
 int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec);
 #else
 static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 6894ec6..045e5d3 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -402,6 +402,9 @@
 {
 	unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
 						AC_VERB_GET_DIGI_CONVERT_1, 0);
+	unsigned char digi2 = digi1 >> 8;
+	unsigned char digi3 = digi1 >> 16;
+
 	snd_iprintf(buffer, "  Digital:");
 	if (digi1 & AC_DIG1_ENABLE)
 		snd_iprintf(buffer, " Enabled");
@@ -419,9 +422,13 @@
 		snd_iprintf(buffer, " Pro");
 	if (digi1 & AC_DIG1_LEVEL)
 		snd_iprintf(buffer, " GenLevel");
+	if (digi3 & AC_DIG3_KAE)
+		snd_iprintf(buffer, " KAE");
 	snd_iprintf(buffer, "\n");
 	snd_iprintf(buffer, "  Digital category: 0x%x\n",
-		    (digi1 >> 8) & AC_DIG2_CC);
+		    digi2 & AC_DIG2_CC);
+	snd_iprintf(buffer, "  IEC Coding Type: 0x%x\n",
+			digi3 & AC_DIG3_ICT);
 }
 
 static const char *get_pwr_state(u32 state)
diff --git a/sound/pci/hda/hda_trace.h b/sound/pci/hda/hda_trace.h
index 9884871..3a1c631 100644
--- a/sound/pci/hda/hda_trace.h
+++ b/sound/pci/hda/hda_trace.h
@@ -58,6 +58,7 @@
 	TP_printk("[%d]", __entry->card)
 );
 
+#ifdef CONFIG_PM
 DECLARE_EVENT_CLASS(hda_power,
 
 	TP_PROTO(struct hda_codec *codec),
@@ -87,6 +88,31 @@
 	TP_ARGS(codec)
 );
 
+TRACE_EVENT(hda_power_count,
+	TP_PROTO(struct hda_codec *codec),
+	TP_ARGS(codec),
+	TP_STRUCT__entry(
+		__field( unsigned int, card )
+		__field( unsigned int, addr )
+		__field( int, power_count )
+		__field( int, power_on )
+		__field( int, power_transition )
+	),
+
+	TP_fast_assign(
+		__entry->card = (codec)->bus->card->number;
+		__entry->addr = (codec)->addr;
+		__entry->power_count = (codec)->power_count;
+		__entry->power_on = (codec)->power_on;
+		__entry->power_transition = (codec)->power_transition;
+	),
+
+	TP_printk("[%d:%d] power_count=%d, power_on=%d, power_transition=%d",
+		  __entry->card, __entry->addr, __entry->power_count,
+		  __entry->power_on, __entry->power_transition)
+);
+#endif /* CONFIG_PM */
+
 TRACE_EVENT(hda_unsol_event,
 
 	TP_PROTO(struct hda_bus *bus, u32 res, u32 res_ex),
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 0208fa12..cdd43ead 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -85,7 +85,7 @@
 	unsigned int analog_beep: 1;	/* analog beep input present */
 	unsigned int avoid_init_slave_vol:1;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	struct hda_loopback_check loopback;
 #endif
 	/* for virtual master */
@@ -269,7 +269,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct ad198x_spec *spec = codec->spec;
@@ -654,10 +654,8 @@
 	.build_pcms = ad198x_build_pcms,
 	.init = ad198x_init,
 	.free = ad198x_free,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	.check_power_status = ad198x_check_power_status,
-#endif
 #ifdef CONFIG_PM
+	.check_power_status = ad198x_check_power_status,
 	.suspend = ad198x_suspend,
 #endif
 	.reboot_notify = ad198x_shutup,
@@ -1231,7 +1229,7 @@
 	{}
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1986a_loopbacks[] = {
 	{ 0x13, HDA_OUTPUT, 0 }, /* Mic */
 	{ 0x14, HDA_OUTPUT, 0 }, /* Phone */
@@ -1278,7 +1276,7 @@
 	spec->mixers[0] = ad1986a_mixers;
 	spec->num_init_verbs = 1;
 	spec->init_verbs[0] = ad1986a_init_verbs;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	spec->loopback.amplist = ad1986a_loopbacks;
 #endif
 	spec->vmaster_nid = 0x1b;
@@ -1537,7 +1535,7 @@
 	{ } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1983_loopbacks[] = {
 	{ 0x12, HDA_OUTPUT, 0 }, /* Mic */
 	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
@@ -1576,7 +1574,7 @@
 	spec->num_init_verbs = 1;
 	spec->init_verbs[0] = ad1983_init_verbs;
 	spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	spec->loopback.amplist = ad1983_loopbacks;
 #endif
 	spec->vmaster_nid = 0x05;
@@ -1704,7 +1702,7 @@
 	{ } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1981_loopbacks[] = {
 	{ 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
 	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
@@ -1812,7 +1810,7 @@
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
-		{ "Docking-Station", 0x1 },
+		{ "Dock Mic", 0x1 },
 		{ "Mix", 0x2 },
 	},
 };
@@ -1836,8 +1834,8 @@
 	 */
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
 	/* FIXME: does this laptop have analog CD connection? */
@@ -1982,7 +1980,7 @@
 	spec->num_init_verbs = 1;
 	spec->init_verbs[0] = ad1981_init_verbs;
 	spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	spec->loopback.amplist = ad1981_loopbacks;
 #endif
 	spec->vmaster_nid = 0x05;
@@ -2807,7 +2805,7 @@
 		snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
 } 
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1988_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Line */
@@ -3399,7 +3397,7 @@
 		codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
 		break;
 	}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	spec->loopback.amplist = ad1988_loopbacks;
 #endif
 	spec->vmaster_nid = 0x04;
@@ -3555,7 +3553,7 @@
 	{ } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1884_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
@@ -3567,7 +3565,7 @@
 
 static const char * const ad1884_slave_vols[] = {
 	"PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
-	"Internal Mic", "Docking Mic", /* "Beep", */ "IEC958",
+	"Internal Mic", "Dock Mic", /* "Beep", */ "IEC958",
 	NULL
 };
 
@@ -3602,7 +3600,7 @@
 	spec->num_init_verbs = 1;
 	spec->init_verbs[0] = ad1884_init_verbs;
 	spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	spec->loopback.amplist = ad1884_loopbacks;
 #endif
 	spec->vmaster_nid = 0x04;
@@ -3628,7 +3626,7 @@
 		{ "Mic", 0x0 },
 		{ "Internal Mic", 0x1 },
 		{ "Mix", 0x3 },
-		{ "Docking-Station", 0x4 },
+		{ "Dock Mic", 0x4 },
 	},
 };
 
@@ -3657,8 +3655,8 @@
 	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
 	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
-	HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
@@ -3994,7 +3992,7 @@
 	{ } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1884a_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
@@ -4602,7 +4600,7 @@
 	spec->num_init_verbs = 1;
 	spec->init_verbs[0] = ad1884a_init_verbs;
 	spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	spec->loopback.amplist = ad1884a_loopbacks;
 #endif
 	codec->patch_ops = ad198x_patch_ops;
@@ -4814,6 +4812,32 @@
 	{ } /* end */
 };
 
+/* simple auto-mute control for AD1882 3-stack board */
+#define AD1882_HP_EVENT	0x01
+
+static void ad1882_3stack_automute(struct hda_codec *codec)
+{
+	bool mute = snd_hda_jack_detect(codec, 0x11);
+	snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    mute ? 0 : PIN_OUT);
+}
+
+static int ad1882_3stack_automute_init(struct hda_codec *codec)
+{
+	ad198x_init(codec);
+	ad1882_3stack_automute(codec);
+	return 0;
+}
+
+static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	switch (res >> 26) {
+	case AD1882_HP_EVENT:
+		ad1882_3stack_automute(codec);
+		break;
+	}
+}
+
 static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
@@ -4928,7 +4952,12 @@
 	{ } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+static const struct hda_verb ad1882_3stack_automute_verbs[] = {
+	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT},
+	{ } /* end */
+};
+
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1882_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
@@ -4942,12 +4971,14 @@
 enum {
 	AD1882_3STACK,
 	AD1882_6STACK,
+	AD1882_3STACK_AUTOMUTE,
 	AD1882_MODELS
 };
 
 static const char * const ad1882_models[AD1986A_MODELS] = {
 	[AD1882_3STACK]		= "3stack",
 	[AD1882_6STACK]		= "6stack",
+	[AD1882_3STACK_AUTOMUTE] = "3stack-automute",
 };
 
 
@@ -4989,7 +5020,7 @@
 	spec->num_init_verbs = 1;
 	spec->init_verbs[0] = ad1882_init_verbs;
 	spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	spec->loopback.amplist = ad1882_loopbacks;
 #endif
 	spec->vmaster_nid = 0x04;
@@ -5002,6 +5033,7 @@
 	switch (board_config) {
 	default:
 	case AD1882_3STACK:
+	case AD1882_3STACK_AUTOMUTE:
 		spec->num_mixers = 3;
 		spec->mixers[2] = ad1882_3stack_mixers;
 		spec->channel_mode = ad1882_modes;
@@ -5009,6 +5041,12 @@
 		spec->need_dac_fix = 1;
 		spec->multiout.max_channels = 2;
 		spec->multiout.num_dacs = 1;
+		if (board_config != AD1882_3STACK) {
+			spec->init_verbs[spec->num_init_verbs++] =
+				ad1882_3stack_automute_verbs;
+			codec->patch_ops.unsol_event = ad1882_3stack_unsol_event;
+			codec->patch_ops.init = ad1882_3stack_automute_init;
+		}
 		break;
 	case AD1882_6STACK:
 		spec->num_mixers = 3;
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 0c4c1a6..fcfc9f0a 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -34,7 +34,8 @@
  */
 
 struct cs_spec {
-	int board_config;
+	struct hda_gen_spec gen;
+
 	struct auto_pin_cfg autocfg;
 	struct hda_multi_out multiout;
 	struct snd_kcontrol *vmaster_sw;
@@ -80,16 +81,20 @@
 	CS420X_MBP53,
 	CS420X_MBP55,
 	CS420X_IMAC27,
-	CS420X_IMAC27_122,
-	CS420X_APPLE,
+	CS420X_GPIO_13,
+	CS420X_GPIO_23,
+	CS420X_MBP101,
+	CS420X_MBP101_COEF,
 	CS420X_AUTO,
-	CS420X_MODELS
+	/* aliases */
+	CS420X_IMAC27_122 = CS420X_GPIO_23,
+	CS420X_APPLE = CS420X_GPIO_13,
 };
 
 /* CS421x boards */
 enum {
 	CS421X_CDB4210,
-	CS421X_MODELS
+	CS421X_SENSE_B,
 };
 
 /* Vendor-specific processing widget */
@@ -1157,6 +1162,14 @@
 	{} /* terminator */
 };
 
+static const struct hda_verb mbp101_init_verbs[] = {
+	{0x11, AC_VERB_SET_COEF_INDEX, 0x0002},
+	{0x11, AC_VERB_SET_PROC_COEF, 0x100a},
+	{0x11, AC_VERB_SET_COEF_INDEX, 0x0004},
+	{0x11, AC_VERB_SET_PROC_COEF, 0x000f},
+	{}
+};
+
 /* SPDIF setup */
 static void init_digital(struct hda_codec *codec)
 {
@@ -1193,7 +1206,6 @@
 	init_output(codec);
 	init_input(codec);
 	init_digital(codec);
-	snd_hda_jack_report_sync(codec);
 
 	return 0;
 }
@@ -1279,38 +1291,32 @@
 	return 0;
 }
 
-static const char * const cs420x_models[CS420X_MODELS] = {
-	[CS420X_MBP53] = "mbp53",
-	[CS420X_MBP55] = "mbp55",
-	[CS420X_IMAC27] = "imac27",
-	[CS420X_IMAC27_122] = "imac27_122",
-	[CS420X_APPLE] = "apple",
-	[CS420X_AUTO] = "auto",
+static const struct hda_model_fixup cs420x_models[] = {
+	{ .id = CS420X_MBP53, .name = "mbp53" },
+	{ .id = CS420X_MBP55, .name = "mbp55" },
+	{ .id = CS420X_IMAC27, .name = "imac27" },
+	{ .id = CS420X_IMAC27_122, .name = "imac27_122" },
+	{ .id = CS420X_APPLE, .name = "apple" },
+	{ .id = CS420X_MBP101, .name = "mbp101" },
+	{}
 };
 
-
-static const struct snd_pci_quirk cs420x_cfg_tbl[] = {
+static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
 	SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
 	SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
 	SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
 	/* this conflicts with too many other models */
 	/*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
-	{} /* terminator */
-};
 
-static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = {
+	/* codec SSID */
 	SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
+	SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
 	SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
 	{} /* terminator */
 };
 
-struct cs_pincfg {
-	hda_nid_t nid;
-	u32 val;
-};
-
-static const struct cs_pincfg mbp53_pincfgs[] = {
+static const struct hda_pintbl mbp53_pincfgs[] = {
 	{ 0x09, 0x012b4050 },
 	{ 0x0a, 0x90100141 },
 	{ 0x0b, 0x90100140 },
@@ -1324,7 +1330,7 @@
 	{} /* terminator */
 };
 
-static const struct cs_pincfg mbp55_pincfgs[] = {
+static const struct hda_pintbl mbp55_pincfgs[] = {
 	{ 0x09, 0x012b4030 },
 	{ 0x0a, 0x90100121 },
 	{ 0x0b, 0x90100120 },
@@ -1338,7 +1344,7 @@
 	{} /* terminator */
 };
 
-static const struct cs_pincfg imac27_pincfgs[] = {
+static const struct hda_pintbl imac27_pincfgs[] = {
 	{ 0x09, 0x012b4050 },
 	{ 0x0a, 0x90100140 },
 	{ 0x0b, 0x90100142 },
@@ -1352,22 +1358,78 @@
 	{} /* terminator */
 };
 
-static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
-	[CS420X_MBP53] = mbp53_pincfgs,
-	[CS420X_MBP55] = mbp55_pincfgs,
-	[CS420X_IMAC27] = imac27_pincfgs,
+static const struct hda_pintbl mbp101_pincfgs[] = {
+	{ 0x0d, 0x40ab90f0 },
+	{ 0x0e, 0x90a600f0 },
+	{ 0x12, 0x50a600f0 },
+	{} /* terminator */
 };
 
-static void fix_pincfg(struct hda_codec *codec, int model,
-		       const struct cs_pincfg **pin_configs)
+static void cs420x_fixup_gpio_13(struct hda_codec *codec,
+				 const struct hda_fixup *fix, int action)
 {
-	const struct cs_pincfg *cfg = pin_configs[model];
-	if (!cfg)
-		return;
-	for (; cfg->nid; cfg++)
-		snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		struct cs_spec *spec = codec->spec;
+		spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
+		spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+		spec->gpio_mask = spec->gpio_dir =
+			spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+	}
 }
 
+static void cs420x_fixup_gpio_23(struct hda_codec *codec,
+				 const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		struct cs_spec *spec = codec->spec;
+		spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
+		spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+		spec->gpio_mask = spec->gpio_dir =
+			spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+	}
+}
+
+static const struct hda_fixup cs420x_fixups[] = {
+	[CS420X_MBP53] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = mbp53_pincfgs,
+		.chained = true,
+		.chain_id = CS420X_APPLE,
+	},
+	[CS420X_MBP55] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = mbp55_pincfgs,
+		.chained = true,
+		.chain_id = CS420X_GPIO_13,
+	},
+	[CS420X_IMAC27] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = imac27_pincfgs,
+		.chained = true,
+		.chain_id = CS420X_GPIO_13,
+	},
+	[CS420X_GPIO_13] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = cs420x_fixup_gpio_13,
+	},
+	[CS420X_GPIO_23] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = cs420x_fixup_gpio_23,
+	},
+	[CS420X_MBP101] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = mbp101_pincfgs,
+		.chained = true,
+		.chain_id = CS420X_MBP101_COEF,
+	},
+	[CS420X_MBP101_COEF] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = mbp101_init_verbs,
+		.chained = true,
+		.chain_id = CS420X_GPIO_13,
+	},
+};
+
 static int patch_cs420x(struct hda_codec *codec)
 {
 	struct cs_spec *spec;
@@ -1380,33 +1442,9 @@
 
 	spec->vendor_nid = CS420X_VENDOR_NID;
 
-	spec->board_config =
-		snd_hda_check_board_config(codec, CS420X_MODELS,
-					   cs420x_models, cs420x_cfg_tbl);
-	if (spec->board_config < 0)
-		spec->board_config =
-			snd_hda_check_board_codec_sid_config(codec,
-				CS420X_MODELS, NULL, cs420x_codec_cfg_tbl);
-	if (spec->board_config >= 0)
-		fix_pincfg(codec, spec->board_config, cs_pincfgs);
-
-	switch (spec->board_config) {
-	case CS420X_IMAC27:
-	case CS420X_MBP53:
-	case CS420X_MBP55:
-	case CS420X_APPLE:
-		spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
-		spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
-		spec->gpio_mask = spec->gpio_dir =
-			spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
-		break;
-	case CS420X_IMAC27_122:
-		spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
-		spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
-		spec->gpio_mask = spec->gpio_dir =
-			spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
-		break;
-	}
+	snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
+			   cs420x_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	err = cs_parse_auto_config(codec);
 	if (err < 0)
@@ -1414,6 +1452,8 @@
 
 	codec->patch_ops = cs_patch_ops;
 
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
 	return 0;
 
  error:
@@ -1431,11 +1471,12 @@
 */
 
 /* CS4210 board names */
-static const char *cs421x_models[CS421X_MODELS] = {
-	[CS421X_CDB4210] = "cdb4210",
+static const struct hda_model_fixup cs421x_models[] = {
+	{ .id = CS421X_CDB4210, .name = "cdb4210" },
+	{}
 };
 
-static const struct snd_pci_quirk cs421x_cfg_tbl[] = {
+static const struct snd_pci_quirk cs421x_fixup_tbl[] = {
 	/* Test Intel board + CDB2410  */
 	SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
 	{} /* terminator */
@@ -1443,7 +1484,7 @@
 
 /* CS4210 board pinconfigs */
 /* Default CS4210 (CDB4210)*/
-static const struct cs_pincfg cdb4210_pincfgs[] = {
+static const struct hda_pintbl cdb4210_pincfgs[] = {
 	{ 0x05, 0x0321401f },
 	{ 0x06, 0x90170010 },
 	{ 0x07, 0x03813031 },
@@ -1453,8 +1494,26 @@
 	{} /* terminator */
 };
 
-static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = {
-	[CS421X_CDB4210] = cdb4210_pincfgs,
+/* Setup GPIO/SENSE for each board (if used) */
+static void cs421x_fixup_sense_b(struct hda_codec *codec,
+				 const struct hda_fixup *fix, int action)
+{
+	struct cs_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+		spec->sense_b = 1;
+}
+
+static const struct hda_fixup cs421x_fixups[] = {
+	[CS421X_CDB4210] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = cdb4210_pincfgs,
+		.chained = true,
+		.chain_id = CS421X_SENSE_B,
+	},
+	[CS421X_SENSE_B] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = cs421x_fixup_sense_b,
+	}
 };
 
 static const struct hda_verb cs421x_coef_init_verbs[] = {
@@ -1643,7 +1702,6 @@
 	init_output(codec);
 	init_input(codec);
 	init_cs421x_digital(codec);
-	snd_hda_jack_report_sync(codec);
 
 	return 0;
 }
@@ -1937,26 +1995,9 @@
 
 	spec->vendor_nid = CS4210_VENDOR_NID;
 
-	spec->board_config =
-		snd_hda_check_board_config(codec, CS421X_MODELS,
-					   cs421x_models, cs421x_cfg_tbl);
-	if (spec->board_config >= 0)
-		fix_pincfg(codec, spec->board_config, cs421x_pincfgs);
-	/*
-	    Setup GPIO/SENSE for each board (if used)
-	*/
-	switch (spec->board_config) {
-	case CS421X_CDB4210:
-		snd_printd("CS4210 board: %s\n",
-			cs421x_models[spec->board_config]);
-/*		spec->gpio_mask = 3;
-		spec->gpio_dir = 3;
-		spec->gpio_data = 3;
-*/
-		spec->sense_b = 1;
-
-		break;
-	}
+	snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
+			   cs421x_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	/*
 	    Update the GPIO/DMIC/SENSE_B pinmux before the configuration
@@ -1971,6 +2012,8 @@
 
 	codec->patch_ops = cs421x_patch_ops;
 
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
 	return 0;
 
  error:
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 5e22a8f..c03d3b8e 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -553,7 +553,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int conexant_suspend(struct hda_codec *codec)
 {
 	snd_hda_shutup_pins(codec);
@@ -567,7 +567,7 @@
 	.init = conexant_init,
 	.free = conexant_free,
 	.set_power_state = conexant_set_power,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	.suspend = conexant_suspend,
 #endif
 	.reboot_notify = snd_hda_shutup_pins,
@@ -1710,8 +1710,8 @@
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Dock Mic Volume", 0x15, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Dock Mic Switch", 0x15, 0x00, HDA_INPUT),
 	{}
 };
 
@@ -3540,8 +3540,9 @@
 				     hda_nid_t pin, hda_nid_t *srcp,
 				     bool do_select, int depth)
 {
+	struct conexant_spec *spec = codec->spec;
 	hda_nid_t conn[HDA_MAX_NUM_INPUTS];
-	int i, nums;
+	int startidx, i, nums;
 
 	switch (get_wcaps_type(get_wcaps(codec, mux))) {
 	case AC_WID_AUD_IN:
@@ -3565,14 +3566,25 @@
 	depth++;
 	if (depth == 2)
 		return -1;
+
+	/* Try to rotate around connections to avoid one boost controlling
+	   another input path as well */
+	startidx = 0;
+	for (i = 0; i < spec->private_imux.num_items; i++)
+		if (spec->imux_info[i].pin == pin) {
+			startidx = i;
+			break;
+		}
+
 	for (i = 0; i < nums; i++) {
-		int ret  = __select_input_connection(codec, conn[i], pin, srcp,
+		int j = (i + startidx) % nums;
+		int ret  = __select_input_connection(codec, conn[j], pin, srcp,
 						     do_select, depth);
 		if (ret >= 0) {
 			if (do_select)
 				snd_hda_codec_write(codec, mux, 0,
-						    AC_VERB_SET_CONNECT_SEL, i);
-			return i;
+						    AC_VERB_SET_CONNECT_SEL, j);
+			return j;
 		}
 	}
 	return -1;
@@ -4061,7 +4073,6 @@
 	cx_auto_init_output(codec);
 	cx_auto_init_input(codec);
 	cx_auto_init_digital(codec);
-	snd_hda_jack_report_sync(codec);
 	snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
 	return 0;
 }
@@ -4396,7 +4407,7 @@
 	.init = cx_auto_init,
 	.free = conexant_free,
 	.unsol_event = cx_auto_unsol_event,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	.suspend = conexant_suspend,
 #endif
 	.reboot_notify = snd_hda_shutup_pins,
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 8f23374..71555cc5 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -34,6 +34,8 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
+#include <sound/asoundef.h>
+#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_jack.h"
@@ -71,6 +73,9 @@
 	struct hdmi_eld sink_eld;
 	struct delayed_work work;
 	int repoll_count;
+	bool non_pcm;
+	bool chmap_set;		/* channel-map override by ALSA API? */
+	unsigned char chmap[8]; /* ALSA API channel-map */
 };
 
 struct hdmi_spec {
@@ -80,6 +85,7 @@
 	int num_pins;
 	struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
 	struct hda_pcm pcm_rec[MAX_HDMI_PINS];
+	unsigned int channels_max; /* max over all cvts */
 
 	/*
 	 * Non-generic ATI/NVIDIA specific
@@ -469,6 +475,17 @@
 	}
 }
 
+static int get_channel_allocation_order(int ca)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+		if (channel_allocations[i].ca_index == ca)
+			break;
+	}
+	return i;
+}
+
 /*
  * The transformation takes two steps:
  *
@@ -535,24 +552,36 @@
 }
 
 
-static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+static void hdmi_std_setup_channel_mapping(struct hda_codec *codec,
 				       hda_nid_t pin_nid,
+				       bool non_pcm,
 				       int ca)
 {
 	int i;
 	int err;
+	int order;
+	int non_pcm_mapping[8];
+
+	order = get_channel_allocation_order(ca);
 
 	if (hdmi_channel_mapping[ca][1] == 0) {
-		for (i = 0; i < channel_allocations[ca].channels; i++)
+		for (i = 0; i < channel_allocations[order].channels; i++)
 			hdmi_channel_mapping[ca][i] = i | (i << 4);
 		for (; i < 8; i++)
 			hdmi_channel_mapping[ca][i] = 0xf | (i << 4);
 	}
 
+	if (non_pcm) {
+		for (i = 0; i < channel_allocations[order].channels; i++)
+			non_pcm_mapping[i] = i | (i << 4);
+		for (; i < 8; i++)
+			non_pcm_mapping[i] = 0xf | (i << 4);
+	}
+
 	for (i = 0; i < 8; i++) {
 		err = snd_hda_codec_write(codec, pin_nid, 0,
 					  AC_VERB_SET_HDMI_CHAN_SLOT,
-					  hdmi_channel_mapping[ca][i]);
+					  non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]);
 		if (err) {
 			snd_printdd(KERN_NOTICE
 				    "HDMI: channel mapping failed\n");
@@ -563,6 +592,136 @@
 	hdmi_debug_channel_mapping(codec, pin_nid);
 }
 
+struct channel_map_table {
+	unsigned char map;		/* ALSA API channel map position */
+	unsigned char cea_slot;		/* CEA slot value */
+	int spk_mask;			/* speaker position bit mask */
+};
+
+static struct channel_map_table map_tables[] = {
+	{ SNDRV_CHMAP_FL,	0x00,	FL },
+	{ SNDRV_CHMAP_FR,	0x01,	FR },
+	{ SNDRV_CHMAP_RL,	0x04,	RL },
+	{ SNDRV_CHMAP_RR,	0x05,	RR },
+	{ SNDRV_CHMAP_LFE,	0x02,	LFE },
+	{ SNDRV_CHMAP_FC,	0x03,	FC },
+	{ SNDRV_CHMAP_RLC,	0x06,	RLC },
+	{ SNDRV_CHMAP_RRC,	0x07,	RRC },
+	{} /* terminator */
+};
+
+/* from ALSA API channel position to speaker bit mask */
+static int to_spk_mask(unsigned char c)
+{
+	struct channel_map_table *t = map_tables;
+	for (; t->map; t++) {
+		if (t->map == c)
+			return t->spk_mask;
+	}
+	return 0;
+}
+
+/* from ALSA API channel position to CEA slot */
+static int to_cea_slot(unsigned char c)
+{
+	struct channel_map_table *t = map_tables;
+	for (; t->map; t++) {
+		if (t->map == c)
+			return t->cea_slot;
+	}
+	return 0x0f;
+}
+
+/* from CEA slot to ALSA API channel position */
+static int from_cea_slot(unsigned char c)
+{
+	struct channel_map_table *t = map_tables;
+	for (; t->map; t++) {
+		if (t->cea_slot == c)
+			return t->map;
+	}
+	return 0;
+}
+
+/* from speaker bit mask to ALSA API channel position */
+static int spk_to_chmap(int spk)
+{
+	struct channel_map_table *t = map_tables;
+	for (; t->map; t++) {
+		if (t->spk_mask == spk)
+			return t->map;
+	}
+	return 0;
+}
+
+/* get the CA index corresponding to the given ALSA API channel map */
+static int hdmi_manual_channel_allocation(int chs, unsigned char *map)
+{
+	int i, spks = 0, spk_mask = 0;
+
+	for (i = 0; i < chs; i++) {
+		int mask = to_spk_mask(map[i]);
+		if (mask) {
+			spk_mask |= mask;
+			spks++;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+		if ((chs == channel_allocations[i].channels ||
+		     spks == channel_allocations[i].channels) &&
+		    (spk_mask & channel_allocations[i].spk_mask) ==
+				channel_allocations[i].spk_mask)
+			return channel_allocations[i].ca_index;
+	}
+	return -1;
+}
+
+/* set up the channel slots for the given ALSA API channel map */
+static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec,
+					     hda_nid_t pin_nid,
+					     int chs, unsigned char *map)
+{
+	int i;
+	for (i = 0; i < 8; i++) {
+		int val, err;
+		if (i < chs)
+			val = to_cea_slot(map[i]);
+		else
+			val = 0xf;
+		val |= (i << 4);
+		err = snd_hda_codec_write(codec, pin_nid, 0,
+					  AC_VERB_SET_HDMI_CHAN_SLOT, val);
+		if (err)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* store ALSA API channel map from the current default map */
+static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
+{
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (i < channel_allocations[ca].channels)
+			map[i] = from_cea_slot((hdmi_channel_mapping[ca][i] >> 4) & 0x0f);
+		else
+			map[i] = 0;
+	}
+}
+
+static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+				       hda_nid_t pin_nid, bool non_pcm, int ca,
+				       int channels, unsigned char *map)
+{
+	if (!non_pcm && map) {
+		hdmi_manual_setup_channel_mapping(codec, pin_nid,
+						  channels, map);
+	} else {
+		hdmi_std_setup_channel_mapping(codec, pin_nid, non_pcm, ca);
+		hdmi_setup_fake_chmap(map, ca);
+	}
+}
 
 /*
  * Audio InfoFrame routines
@@ -686,7 +845,8 @@
 }
 
 static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
-					struct snd_pcm_substream *substream)
+				       bool non_pcm,
+				       struct snd_pcm_substream *substream)
 {
 	struct hdmi_spec *spec = codec->spec;
 	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
@@ -700,7 +860,12 @@
 	if (!eld->monitor_present)
 		return;
 
-	ca = hdmi_channel_allocation(eld, channels);
+	if (!non_pcm && per_pin->chmap_set)
+		ca = hdmi_manual_channel_allocation(channels, per_pin->chmap);
+	else
+		ca = hdmi_channel_allocation(eld, channels);
+	if (ca < 0)
+		ca = 0;
 
 	memset(&ai, 0, sizeof(ai));
 	if (eld->conn_type == 0) { /* HDMI */
@@ -737,12 +902,21 @@
 			    "pin=%d channels=%d\n",
 			    pin_nid,
 			    channels);
-		hdmi_setup_channel_mapping(codec, pin_nid, ca);
+		hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
+					   channels, per_pin->chmap);
 		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);
+	} else {
+		/* For non-pcm audio switch, setup new channel mapping
+		 * accordingly */
+		if (per_pin->non_pcm != non_pcm)
+			hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
+						   channels, per_pin->chmap);
 	}
+
+	per_pin->non_pcm = non_pcm;
 }
 
 
@@ -1035,6 +1209,7 @@
 	per_pin = &spec->pins[pin_idx];
 
 	per_pin->pin_nid = pin_nid;
+	per_pin->non_pcm = false;
 
 	err = hdmi_read_pin_conn(codec, pin_idx);
 	if (err < 0)
@@ -1064,8 +1239,11 @@
 
 	per_cvt->cvt_nid = cvt_nid;
 	per_cvt->channels_min = 2;
-	if (chans <= 16)
+	if (chans <= 16) {
 		per_cvt->channels_max = chans;
+		if (chans > spec->channels_max)
+			spec->channels_max = chans;
+	}
 
 	err = snd_hda_query_supported_pcm(codec, cvt_nid,
 					  &per_cvt->rates,
@@ -1115,7 +1293,7 @@
 	 * can be lost and presence sense verb will become inaccurate if the
 	 * HDA link is powered off at hot plug or hw initialization time.
 	 */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
 	      AC_PWRST_EPSS))
 		codec->bus->power_keep_link_on = 1;
@@ -1133,6 +1311,19 @@
 	return &names[idx][0];
 }
 
+static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
+{
+	struct hda_spdif_out *spdif;
+	bool non_pcm;
+
+	mutex_lock(&codec->spdif_mutex);
+	spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid);
+	non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO);
+	mutex_unlock(&codec->spdif_mutex);
+	return non_pcm;
+}
+
+
 /*
  * HDMI callbacks
  */
@@ -1148,10 +1339,13 @@
 	int pin_idx = hinfo_to_pin_index(spec, hinfo);
 	hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
 	int pinctl;
+	bool non_pcm;
+
+	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
 
 	hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
 
-	hdmi_setup_audio_infoframe(codec, pin_idx, substream);
+	hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream);
 
 	pinctl = snd_hda_codec_read(codec, pin_nid, 0,
 				    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -1200,7 +1394,10 @@
 				    AC_VERB_SET_PIN_WIDGET_CONTROL,
 				    pinctl & ~PIN_OUT);
 		snd_hda_spdif_ctls_unassign(codec, pin_idx);
+		per_pin->chmap_set = false;
+		memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
 	}
+
 	return 0;
 }
 
@@ -1211,6 +1408,135 @@
 	.cleanup = generic_hdmi_playback_pcm_cleanup,
 };
 
+/*
+ * ALSA API channel-map control callbacks
+ */
+static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *uinfo)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	struct hda_codec *codec = info->private_data;
+	struct hdmi_spec *spec = codec->spec;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = spec->channels_max;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+	return 0;
+}
+
+static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+			      unsigned int size, unsigned int __user *tlv)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	struct hda_codec *codec = info->private_data;
+	struct hdmi_spec *spec = codec->spec;
+	const unsigned int valid_mask =
+		FL | FR | RL | RR | LFE | FC | RLC | RRC;
+	unsigned int __user *dst;
+	int chs, count = 0;
+
+	if (size < 8)
+		return -ENOMEM;
+	if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+		return -EFAULT;
+	size -= 8;
+	dst = tlv + 2;
+	for (chs = 2; chs <= spec->channels_max; chs++) {
+		int i, c;
+		struct cea_channel_speaker_allocation *cap;
+		cap = channel_allocations;
+		for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) {
+			int chs_bytes = chs * 4;
+			if (cap->channels != chs)
+				continue;
+			if (cap->spk_mask & ~valid_mask)
+				continue;
+			if (size < 8)
+				return -ENOMEM;
+			if (put_user(SNDRV_CTL_TLVT_CHMAP_VAR, dst) ||
+			    put_user(chs_bytes, dst + 1))
+				return -EFAULT;
+			dst += 2;
+			size -= 8;
+			count += 8;
+			if (size < chs_bytes)
+				return -ENOMEM;
+			size -= chs_bytes;
+			count += chs_bytes;
+			for (c = 7; c >= 0; c--) {
+				int spk = cap->speakers[c];
+				if (!spk)
+					continue;
+				if (put_user(spk_to_chmap(spk), dst))
+					return -EFAULT;
+				dst++;
+			}
+		}
+	}
+	if (put_user(count, tlv + 1))
+		return -EFAULT;
+	return 0;
+}
+
+static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	struct hda_codec *codec = info->private_data;
+	struct hdmi_spec *spec = codec->spec;
+	int pin_idx = kcontrol->private_value;
+	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++)
+		ucontrol->value.integer.value[i] = per_pin->chmap[i];
+	return 0;
+}
+
+static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	struct hda_codec *codec = info->private_data;
+	struct hdmi_spec *spec = codec->spec;
+	int pin_idx = kcontrol->private_value;
+	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+	unsigned int ctl_idx;
+	struct snd_pcm_substream *substream;
+	unsigned char chmap[8];
+	int i, ca, prepared = 0;
+
+	ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	substream = snd_pcm_chmap_substream(info, ctl_idx);
+	if (!substream || !substream->runtime)
+		return -EBADFD;
+	switch (substream->runtime->status->state) {
+	case SNDRV_PCM_STATE_OPEN:
+	case SNDRV_PCM_STATE_SETUP:
+		break;
+	case SNDRV_PCM_STATE_PREPARED:
+		prepared = 1;
+		break;
+	default:
+		return -EBUSY;
+	}
+	memset(chmap, 0, sizeof(chmap));
+	for (i = 0; i < ARRAY_SIZE(chmap); i++)
+		chmap[i] = ucontrol->value.integer.value[i];
+	if (!memcmp(chmap, per_pin->chmap, sizeof(chmap)))
+		return 0;
+	ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap);
+	if (ca < 0)
+		return -EINVAL;
+	per_pin->chmap_set = true;
+	memcpy(per_pin->chmap, chmap, sizeof(chmap));
+	if (prepared)
+		hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm,
+					   substream);
+
+	return 0;
+}
+
 static int generic_hdmi_build_pcms(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
@@ -1223,6 +1549,7 @@
 		info = &spec->pcm_rec[pin_idx];
 		info->name = get_hdmi_pcm_name(pin_idx);
 		info->pcm_type = HDA_PCM_TYPE_HDMI;
+		info->own_chmap = true;
 
 		pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
 		pstr->substreams = 1;
@@ -1280,6 +1607,27 @@
 		hdmi_present_sense(per_pin, 0);
 	}
 
+	/* add channel maps */
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct snd_pcm_chmap *chmap;
+		struct snd_kcontrol *kctl;
+		int i;
+		err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm,
+					     SNDRV_PCM_STREAM_PLAYBACK,
+					     NULL, 0, pin_idx, &chmap);
+		if (err < 0)
+			return err;
+		/* override handlers */
+		chmap->private_data = codec;
+		kctl = chmap->kctl;
+		for (i = 0; i < kctl->count; i++)
+			kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+		kctl->info = hdmi_chmap_ctl_info;
+		kctl->get = hdmi_chmap_ctl_get;
+		kctl->put = hdmi_chmap_ctl_put;
+		kctl->tlv.c = hdmi_chmap_ctl_tlv;
+	}
+
 	return 0;
 }
 
@@ -1311,7 +1659,6 @@
 		hdmi_init_pin(codec, pin_nid);
 		snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
 	}
-	snd_hda_jack_report_sync(codec);
 	return 0;
 }
 
@@ -1428,7 +1775,6 @@
 		snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 				    AMP_OUT_UNMUTE);
 	snd_hda_jack_detect_enable(codec, pin, pin);
-	snd_hda_jack_report_sync(codec);
 	return 0;
 }
 
@@ -1809,6 +2155,43 @@
 	return 0;
 }
 
+static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	int err = simple_playback_build_pcms(codec);
+	spec->pcm_rec[0].own_chmap = true;
+	return err;
+}
+
+static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	struct snd_pcm_chmap *chmap;
+	int err;
+
+	err = simple_playback_build_controls(codec);
+	if (err < 0)
+		return err;
+
+	/* add channel maps */
+	err = snd_pcm_add_chmap_ctls(spec->pcm_rec[0].pcm,
+				     SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_alt_chmaps, 8, 0, &chmap);
+	if (err < 0)
+		return err;
+	switch (codec->preset->id) {
+	case 0x10de0002:
+	case 0x10de0003:
+	case 0x10de0005:
+	case 0x10de0006:
+		chmap->channel_mask = (1U << 2) | (1U << 8);
+		break;
+	case 0x10de0007:
+		chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
+	}
+	return 0;
+}
+
 static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
@@ -1819,6 +2202,8 @@
 	spec->multiout.max_channels = 8;
 	spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
 	codec->patch_ops.init = nvhdmi_7x_init_8ch;
+	codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
+	codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
 
 	/* Initialize the audio infoframe channel mask and checksum to something
 	 * valid */
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4f81dd4..3d440fc 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -174,7 +174,7 @@
 
 	/* hooks */
 	void (*init_hook)(struct hda_codec *codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	void (*power_hook)(struct hda_codec *codec);
 #endif
 	void (*shutup)(struct hda_codec *codec);
@@ -215,7 +215,7 @@
 	/* for virtual master */
 	hda_nid_t vmaster_nid;
 	struct hda_vmaster_mute_hook vmaster_mute;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	struct hda_loopback_check loopback;
 	int num_loopbacks;
 	struct hda_amp_list loopback_list[8];
@@ -2053,13 +2053,11 @@
 
 	alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
 
-	snd_hda_jack_report_sync(codec);
-
 	hda_call_check_power_status(codec, 0x01);
 	return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct alc_spec *spec = codec->spec;
@@ -2289,6 +2287,8 @@
 			p = &alc_pcm_analog_playback;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+			spec->multiout.max_channels;
 	}
 	if (spec->adc_nids) {
 		p = spec->stream_analog_capture;
@@ -2437,7 +2437,7 @@
 	snd_hda_detach_beep_device(codec);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static void alc_power_eapd(struct hda_codec *codec)
 {
 	alc_auto_setup_eapd(codec, false);
@@ -2477,7 +2477,7 @@
 #ifdef CONFIG_PM
 	.resume = alc_resume,
 #endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	.suspend = alc_suspend,
 	.check_power_status = alc_check_power_status,
 #endif
@@ -2633,7 +2633,7 @@
 	return channel_name[ch];
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 /* add the powersave loopback-list entry */
 static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx)
 {
@@ -6189,6 +6189,7 @@
 	SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
 	SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
+	SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
 	SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
@@ -6503,7 +6504,7 @@
 	}
 
 	codec->patch_ops = alc_patch_ops;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 	spec->power_hook = alc_power_eapd;
 #endif
 
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 3d4722f..bb6c50e 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -103,6 +103,7 @@
 	STAC_HP_ZEPHYR,
 	STAC_92HD83XXX_HP_LED,
 	STAC_92HD83XXX_HP_INV_LED,
+	STAC_92HD83XXX_HP_MIC_LED,
 	STAC_92HD83XXX_MODELS
 };
 
@@ -215,6 +216,9 @@
 	unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
 	unsigned int vref_led;
 
+	unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
+	bool mic_mute_led_on; /* current mic mute state */
+
 	/* stream */
 	unsigned int stream_delay;
 
@@ -1679,6 +1683,7 @@
 	[STAC_HP_ZEPHYR] = "hp-zephyr",
 	[STAC_92HD83XXX_HP_LED] = "hp-led",
 	[STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led",
+	[STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led",
 };
 
 static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
@@ -1703,6 +1708,8 @@
 			  "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
 			  "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
+			  "HP Folio", STAC_92HD83XXX_HP_MIC_LED),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
 			  "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
@@ -2791,18 +2798,27 @@
 	return knew;
 }
 
+static struct snd_kcontrol_new *
+add_control_temp(struct sigmatel_spec *spec,
+		 const struct snd_kcontrol_new *ktemp,
+		 int idx, const char *name,
+		 unsigned long val)
+{
+	struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
+							 HDA_SUBDEV_AMP_FLAG);
+	if (!knew)
+		return NULL;
+	knew->index = idx;
+	knew->private_value = val;
+	return knew;
+}
+
 static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
 				     const struct snd_kcontrol_new *ktemp,
 				     int idx, const char *name,
 				     unsigned long val)
 {
-	struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
-							 HDA_SUBDEV_AMP_FLAG);
-	if (!knew)
-		return -ENOMEM;
-	knew->index = idx;
-	knew->private_value = val;
-	return 0;
+	return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM;
 }
 
 static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
@@ -3226,9 +3242,12 @@
 				idx = i;
 				break;
 			case AUTO_PIN_SPEAKER_OUT:
-				name = "Speaker";
-				idx = i;
-				break;
+				if (num_outs <= 1) {
+					name = "Speaker";
+					idx = i;
+					break;
+				}
+				/* Fall through in case of multi speaker outs */
 			default:
 				name = chname[i];
 				idx = 0;
@@ -3242,18 +3261,56 @@
 	return 0;
 }
 
+static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
+			  unsigned int dir_mask, unsigned int data);
+
+/* hook for controlling mic-mute LED GPIO */
+static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	int err;
+	bool mute;
+
+	err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+	if (err <= 0)
+		return err;
+	mute = !(ucontrol->value.integer.value[0] &&
+		 ucontrol->value.integer.value[1]);
+	if (spec->mic_mute_led_on != mute) {
+		spec->mic_mute_led_on = mute;
+		if (mute)
+			spec->gpio_data |= spec->mic_mute_led_gpio;
+		else
+			spec->gpio_data &= ~spec->mic_mute_led_gpio;
+		stac_gpio_set(codec, spec->gpio_mask,
+			      spec->gpio_dir, spec->gpio_data);
+	}
+	return err;
+}
+
 static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
 				    unsigned long sw, int idx)
 {
+	struct sigmatel_spec *spec = codec->spec;
+	struct snd_kcontrol_new *knew;
 	int err;
+
 	err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
 				       "Capture Volume", vol);
 	if (err < 0)
 		return err;
-	err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx,
-				       "Capture Switch", sw);
-	if (err < 0)
-		return err;
+
+	knew = add_control_temp(spec,
+				&stac92xx_control_templates[STAC_CTL_WIDGET_MUTE],
+				idx, "Capture Switch", sw);
+	if (!knew)
+		return -ENOMEM;
+	/* add a LED hook for some HP laptops */
+	if (spec->mic_mute_led_gpio)
+		knew->put = stac92xx_capture_sw_put_led;
+
 	return 0;
 }
 
@@ -4418,8 +4475,6 @@
 		stac_toggle_power_map(codec, nid, 0);
 	}
 
-	snd_hda_jack_report_sync(codec);
-
 	/* sync mute LED */
 	if (spec->gpio_led) {
 		if (spec->vmaster_mute.hook)
@@ -5578,6 +5633,9 @@
 	case STAC_92HD83XXX_HP_INV_LED:
 		default_polarity = 1;
 		break;
+	case STAC_92HD83XXX_HP_MIC_LED:
+		spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
+		break;
 	}
 
 	if (find_mute_led_cfg(codec, default_polarity))
@@ -5596,6 +5654,13 @@
 		}
 	}
 
+	if (spec->mic_mute_led_gpio) {
+		spec->gpio_mask |= spec->mic_mute_led_gpio;
+		spec->gpio_dir |= spec->mic_mute_led_gpio;
+		spec->mic_mute_led_on = true;
+		spec->gpio_data |= spec->mic_mute_led_gpio;
+	}
+
 	err = stac92xx_parse_auto_config(codec);
 	if (!err) {
 		if (spec->board_config < 0) {
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 4307717..5a45a91 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -1672,7 +1672,8 @@
 	struct via_spec *spec = codec->spec;
 
 	if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0] &&
-	    (spec->codec_type != VT1708 || spec->vt1708_jack_detect))
+	    (spec->codec_type != VT1708 || spec->vt1708_jack_detect) &&
+	    is_jack_detectable(codec, spec->autocfg.hp_pins[0]))
 		present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
 
 	if (spec->smart51_enabled)
@@ -1764,7 +1765,7 @@
 }
 #endif
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct via_spec *spec = codec->spec;
@@ -1785,8 +1786,6 @@
 	.unsol_event = via_unsol_event,
 #ifdef CONFIG_PM
 	.suspend = via_suspend,
-#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
 	.check_power_status = via_check_power_status,
 #endif
 };
@@ -2815,7 +2814,6 @@
 
 	via_hp_automute(codec);
 	vt1708_update_hp_work(spec);
-	snd_hda_jack_report_sync(codec);
 
 	return 0;
 }
@@ -3669,6 +3667,32 @@
 		update_power_state(codec, 0x21, AC_PWRST_D3);
 }
 
+/*
+ * pin fix-up
+ */
+enum {
+	VIA_FIXUP_INTMIC_BOOST,
+};
+
+static void via_fixup_intmic_boost(struct hda_codec *codec,
+				  const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+		override_mic_boost(codec, 0x30, 0, 2, 40);
+}
+
+static const struct hda_fixup via_fixups[] = {
+	[VIA_FIXUP_INTMIC_BOOST] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = via_fixup_intmic_boost,
+	},
+};
+
+static const struct snd_pci_quirk vt2002p_fixups[] = {
+	SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST),
+	{}
+};
+
 /* patch for vt2002P */
 static int patch_vt2002P(struct hda_codec *codec)
 {
@@ -3685,6 +3709,9 @@
 	override_mic_boost(codec, 0x29, 0, 3, 40);
 	add_secret_dac_path(codec);
 
+	snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
 	/* automatic parse from the BIOS config */
 	err = via_parse_auto_config(codec);
 	if (err < 0) {
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 3e4f8c1..20bcdde 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -2103,7 +2103,7 @@
 /*
  * suspend/resume
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int aureon_resume(struct snd_ice1712 *ice)
 {
 	struct aureon_spec *spec = ice->spec;
@@ -2160,7 +2160,7 @@
 		wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
 	}
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	ice->pm_resume = aureon_resume;
 	ice->pm_suspend_enabled = 1;
 #endif
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index 0da778a..d0e7d87 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -384,7 +384,7 @@
 	char **ext_clock_names;
 	int ext_clock_count;
 	void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	int (*pm_suspend)(struct snd_ice1712 *);
 	int (*pm_resume)(struct snd_ice1712 *);
 	unsigned int pm_suspend_enabled:1;
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index bed9f34..3050a52 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2792,7 +2792,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_vt1724_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -2878,7 +2878,7 @@
 #define SND_VT1724_PM_OPS	&snd_vt1724_pm
 #else
 #define SND_VT1724_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver vt1724_driver = {
 	.name = KBUILD_MODNAME,
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index 98bc3b7..14fd536 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -486,7 +486,7 @@
  * suspend/resume
  * */
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int juli_resume(struct snd_ice1712 *ice)
 {
 	struct snd_akm4xxx *ak = ice->akm;
@@ -652,7 +652,7 @@
 
 	ice->spdif.ops.open = juli_spdif_in_open;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	ice->pm_resume = juli_resume;
 	ice->pm_suspend = juli_suspend;
 	ice->pm_suspend_enabled = 1;
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c
index 075d5aa..7bf093c 100644
--- a/sound/pci/ice1712/prodigy_hifi.c
+++ b/sound/pci/ice1712/prodigy_hifi.c
@@ -1100,7 +1100,7 @@
 		ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int prodigy_hd2_resume(struct snd_ice1712 *ice)
 {
 	/* initialize ak4396 codec and restore previous mixer volumes */
@@ -1141,7 +1141,7 @@
 		return -ENOMEM;
 	ice->spec = spec;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	ice->pm_resume = &prodigy_hd2_resume;
 	ice->pm_suspend_enabled = 1;
 #endif
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index cd553f5..848102e 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -1541,6 +1541,26 @@
 					      snd_dma_pci_data(chip->pci),
 					      rec->prealloc_size, rec->prealloc_max_size);
 
+	if (rec->ac97_idx == ICHD_PCMOUT && rec->playback_ops) {
+		struct snd_pcm_chmap *chmap;
+		int chs = 2;
+		if (rec->ac97_idx == ICHD_PCMOUT) {
+			if (chip->multi8)
+				chs = 8;
+			else if (chip->multi6)
+				chs = 6;
+			else if (chip->multi4)
+				chs = 4;
+		}
+		err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+					     snd_pcm_alt_chmaps, chs, 0,
+					     &chmap);
+		if (err < 0)
+			return err;
+		chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+		chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+	}
+
 	return 0;
 }
 
@@ -2620,7 +2640,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -2741,7 +2761,7 @@
 #define INTEL8X0_PM_OPS	&intel8x0_pm
 #else
 #define INTEL8X0_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #define INTEL8X0_TESTBUF_SIZE	32768	/* enough large for one shot */
 
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index da44bb3..4d55173 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -1008,7 +1008,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1067,7 +1067,7 @@
 #define INTEL8X0M_PM_OPS	&intel8x0m_pm
 #else
 #define INTEL8X0M_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PROC_FS
 static void snd_intel8x0m_proc_read(struct snd_info_entry * entry,
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index e69ce5f..8a67ce95 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -196,8 +196,8 @@
 #define K1212_ADAT_BUF_SIZE	(K1212_ADAT_CHANNELS * 2 * kPlayBufferFrames * kNumBuffers)
 #define K1212_MAX_BUF_SIZE	(K1212_ANALOG_BUF_SIZE + K1212_ADAT_BUF_SIZE)
 
-#define k1212MinADCSens     0x7f
-#define k1212MaxADCSens     0x00
+#define k1212MinADCSens     0x00
+#define k1212MaxADCSens     0x7f
 #define k1212MaxVolume      0x7fff
 #define k1212MaxWaveVolume  0xffff
 #define k1212MinVolume      0x0000
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index c85d1ff..eb3cd3a 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -789,7 +789,7 @@
 
 	unsigned int in_suspend;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	u16 *suspend_mem;
 #endif
 
@@ -2368,7 +2368,7 @@
 		outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
 	}
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	vfree(chip->suspend_mem);
 #endif
 
@@ -2390,7 +2390,7 @@
 /*
  * APM support
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int m3_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -2485,7 +2485,7 @@
 #define M3_PM_OPS	&m3_pm
 #else
 #define M3_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_SND_MAESTRO3_INPUT
 static int __devinit snd_m3_input_register(struct snd_m3 *chip)
@@ -2656,7 +2656,7 @@
 	}
 	chip->irq = pci->irq;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));
 	if (chip->suspend_mem == NULL)
 		snd_printk(KERN_WARNING "can't allocate apm buffer\n");
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 465cff2..e80e9a1 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1377,7 +1377,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * APM event handler, so the card is properly reinitialized after a power
  * event.
@@ -1441,7 +1441,7 @@
 #define NM256_PM_OPS	&nm256_pm
 #else
 #define NM256_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_nm256_free(struct nm256 *chip)
 {
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 37520a2b4..2becae1 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -872,7 +872,7 @@
 	.id_table = oxygen_ids,
 	.probe = generic_oxygen_probe,
 	.remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	.driver = {
 		.pm = &oxygen_pci_pm,
 	},
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 7112a89..09a24b2 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -161,7 +161,7 @@
 				     )
 		    );
 void oxygen_pci_remove(struct pci_dev *pci);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 extern const struct dev_pm_ops oxygen_pci_pm;
 #endif
 void oxygen_pci_shutdown(struct pci_dev *pci);
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index ab8738e..25697584 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -726,7 +726,7 @@
 }
 EXPORT_SYMBOL(oxygen_pci_remove);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int oxygen_pci_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -824,7 +824,7 @@
 
 SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume);
 EXPORT_SYMBOL(oxygen_pci_pm);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 void oxygen_pci_shutdown(struct pci_dev *pci)
 {
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index d3b606b..3d71423 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -93,7 +93,7 @@
 	.id_table = xonar_ids,
 	.probe = xonar_probe,
 	.remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	.driver = {
 		.pm = &oxygen_pci_pm,
 	},
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index e3ac1f7..be4f145 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -91,6 +91,14 @@
 	PCI_ID_PCX924E,
 	PCI_ID_PCX924HRMIC,
 	PCI_ID_PCX924E_MIC,
+	PCI_ID_VX442HR,
+	PCI_ID_PCX442HR,
+	PCI_ID_VX442E,
+	PCI_ID_PCX442E,
+	PCI_ID_VX822HR,
+	PCI_ID_PCX822HR,
+	PCI_ID_VX822E,
+	PCI_ID_PCX822E,
 	PCI_ID_LAST
 };
 
@@ -121,6 +129,14 @@
 	{ 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, },
 	{ 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, },
 	{ 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, },
+	{ 0x10b5, 0x9656, 0x1369, 0xd001, 0, 0, PCI_ID_VX442HR, },
+	{ 0x10b5, 0x9656, 0x1369, 0xd101, 0, 0, PCI_ID_PCX442HR, },
+	{ 0x10b5, 0x9056, 0x1369, 0xd021, 0, 0, PCI_ID_VX442E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xd121, 0, 0, PCI_ID_PCX442E, },
+	{ 0x10b5, 0x9656, 0x1369, 0xd201, 0, 0, PCI_ID_VX822HR, },
+	{ 0x10b5, 0x9656, 0x1369, 0xd301, 0, 0, PCI_ID_PCX822HR, },
+	{ 0x10b5, 0x9056, 0x1369, 0xd221, 0, 0, PCI_ID_VX822E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xd321, 0, 0, PCI_ID_PCX822E, },
 	{ 0, }
 };
 
@@ -160,6 +176,14 @@
 [PCI_ID_PCX924E] =      { "PCX924e",      1, 1, 5, 44 },
 [PCI_ID_PCX924HRMIC] =  { "PCX924HR-Mic", 1, 1, 5, 44 },
 [PCI_ID_PCX924E_MIC] =  { "PCX924e-Mic",  1, 1, 5, 44 },
+[PCI_ID_VX442HR] =      { "VX442HR",      2, 2, 0, 41 },
+[PCI_ID_PCX442HR] =     { "PCX442HR",     2, 2, 0, 41 },
+[PCI_ID_VX442E] =       { "VX442e",       2, 2, 1, 41 },
+[PCI_ID_PCX442E] =      { "PCX442e",      2, 2, 1, 41 },
+[PCI_ID_VX822HR] =      { "VX822HR",      4, 1, 2, 42 },
+[PCI_ID_PCX822HR] =     { "PCX822HR",     4, 1, 2, 42 },
+[PCI_ID_VX822E] =       { "VX822e",       4, 1, 3, 42 },
+[PCI_ID_PCX822E] =      { "PCX822e",      4, 1, 3, 42 },
 };
 
 /* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index ec1587c..bf207e3 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -66,10 +66,10 @@
 	err = pcxhr_send_msg(mgr, &rmh);
 	if (err)
 		return err;
-	/* test 8 or 12 phys out */
-	if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2)
+	/* test 4, 8 or 12 phys out */
+	if ((rmh.stat[0] & MASK_FIRST_FIELD) < mgr->playback_chips * 2)
 		return -EINVAL;
-	/* test 8 or 2 phys in */
+	/* test 4, 8 or 2 phys in */
 	if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) <
 	    mgr->capture_chips * 2)
 		return -EINVAL;
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 760ee46..7d29154 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -464,7 +464,7 @@
 
 	unsigned long received_irqs;
 	unsigned long handled_irqs;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	int in_suspend;
 #endif
 };
@@ -1150,7 +1150,7 @@
 	}
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int riptide_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -1193,7 +1193,7 @@
 #define RIPTIDE_PM_OPS	&riptide_pm
 #else
 #define RIPTIDE_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
 {
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 805ab6e..51e4340 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -103,7 +103,7 @@
  * we're not doing power management, we still need to allocate a page
  * for the silence buffer.
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 #define SIS_SUSPEND_PAGES	4
 #else
 #define SIS_SUSPEND_PAGES	1
@@ -1208,7 +1208,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int sis_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -1305,7 +1305,7 @@
 #define SIS_PM_OPS	&sis_pm
 #else
 #define SIS_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int sis_alloc_suspend(struct sis7019 *sis)
 {
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index d36e6ca..8a6f1f7 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -177,7 +177,7 @@
 	.id_table = snd_trident_ids,
 	.probe = snd_trident_probe,
 	.remove = __devexit_p(snd_trident_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	.driver = {
 		.pm = &snd_trident_pm,
 	},
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 94011dc..06b10d1 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -3919,7 +3919,7 @@
 	}
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_trident_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
@@ -3983,4 +3983,4 @@
 }
 
 SIMPLE_DEV_PM_OPS(snd_trident_pm, snd_trident_suspend, snd_trident_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 0eb7245..f0b4efd 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -362,7 +362,7 @@
 
 	unsigned char old_legacy;
 	unsigned char old_legacy_cfg;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	unsigned char legacy_saved;
 	unsigned char legacy_cfg_saved;
 	unsigned char spdif_ctrl_saved;
@@ -1440,6 +1440,7 @@
 static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
 {
 	struct snd_pcm *pcm;
+	struct snd_pcm_chmap *chmap;
 	int i, err;
 
 	chip->playback_devno = 0;	/* x 4 */
@@ -1467,6 +1468,12 @@
 					      snd_dma_pci_data(chip->pci),
 					      64*1024, VIA_MAX_BUFSIZE);
 
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_std_chmaps, 2, 0,
+				     &chmap);
+	if (err < 0)
+		return err;
+
 	/* PCM #1:  multi-channel playback and 2nd capture */
 	err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 1, &pcm);
 	if (err < 0)
@@ -1484,6 +1491,14 @@
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 					      snd_dma_pci_data(chip->pci),
 					      64*1024, VIA_MAX_BUFSIZE);
+
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_alt_chmaps, 6, 0,
+				     &chmap);
+	if (err < 0)
+		return err;
+	chip->ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+
 	return 0;
 }
 
@@ -1493,6 +1508,7 @@
 static int __devinit snd_via8233a_pcm_new(struct via82xx *chip)
 {
 	struct snd_pcm *pcm;
+	struct snd_pcm_chmap *chmap;
 	int err;
 
 	chip->multi_devno = 0;
@@ -1519,6 +1535,13 @@
 					      snd_dma_pci_data(chip->pci),
 					      64*1024, VIA_MAX_BUFSIZE);
 
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_alt_chmaps, 6, 0,
+				     &chmap);
+	if (err < 0)
+		return err;
+	chip->ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+
 	/* SPDIF supported? */
 	if (! ac97_can_spdif(chip->ac97))
 		return 0;
@@ -2038,7 +2061,7 @@
 		if (mpu_port >= 0x200) {	/* force MIDI */
 			mpu_port &= 0xfffc;
 			pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 			chip->mpu_port_saved = mpu_port;
 #endif
 		} else {
@@ -2090,7 +2113,7 @@
 
 	snd_via686_create_gameport(chip, &legacy);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	chip->legacy_saved = legacy;
 	chip->legacy_cfg_saved = legacy_cfg;
 #endif
@@ -2238,7 +2261,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -2313,7 +2336,7 @@
 #define SND_VIA82XX_PM_OPS	&snd_via82xx_pm
 #else
 #define SND_VIA82XX_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_via82xx_free(struct via82xx *chip)
 {
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index e886bc1..8e0efc4 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -1019,7 +1019,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1076,7 +1076,7 @@
 #define SND_VIA82XX_PM_OPS	&snd_via82xx_pm
 #else
 #define SND_VIA82XX_PM_OPS	NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_via82xx_free(struct via82xx_modem *chip)
 {
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index b89e7a8..fdfbaf857 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -257,7 +257,7 @@
 	pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_vx222_suspend(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 4810356..e01fe34 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -355,7 +355,7 @@
 	.id_table = snd_ymfpci_ids,
 	.probe = snd_card_ymfpci_probe,
 	.remove = __devexit_p(snd_card_ymfpci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	.driver = {
 		.pm = &snd_ymfpci_pm,
 	},
diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h
index bddc405..4631a23 100644
--- a/sound/pci/ymfpci/ymfpci.h
+++ b/sound/pci/ymfpci/ymfpci.h
@@ -363,7 +363,7 @@
 	const struct firmware *dsp_microcode;
 	const struct firmware *controller_microcode;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	u32 *saved_regs;
 	u32 saved_ydsxgr_mode;
 	u16 saved_dsxg_legacy;
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 62b2363..3a6f03f 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -1166,6 +1166,11 @@
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_std_chmaps, 2, 0, NULL);
+	if (err < 0)
+		return err;
+
 	if (rpcm)
 		*rpcm = pcm;
 	return 0;
@@ -1257,6 +1262,14 @@
 	.pointer =		snd_ymfpci_playback_pointer,
 };
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+	{ .channels = 1,
+	  .map = { SNDRV_CHMAP_MONO } },
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ }
+};
+
 int __devinit snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm)
 {
 	struct snd_pcm *pcm;
@@ -1278,6 +1291,11 @@
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				     surround_map, 2, 0, NULL);
+	if (err < 0)
+		return err;
+
 	if (rpcm)
 		*rpcm = pcm;
 	return 0;
@@ -2242,7 +2260,7 @@
 	pci_set_power_state(chip->pci, 3);
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	vfree(chip->saved_regs);
 #endif
 	if (chip->irq >= 0)
@@ -2272,7 +2290,7 @@
 	return snd_ymfpci_free(chip);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int saved_regs_index[] = {
 	/* spdif */
 	YDSXGR_SPDIFOUTCTRL,
@@ -2374,7 +2392,7 @@
 }
 
 SIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 int __devinit snd_ymfpci_create(struct snd_card *card,
 				struct pci_dev * pci,
@@ -2452,7 +2470,7 @@
 		return err;
 	}
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 	chip->saved_regs = vmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32));
 	if (chip->saved_regs == NULL) {
 		snd_ymfpci_free(chip);
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
index 5df529e..bbc1257 100644
--- a/sound/soc/soc-dmaengine-pcm.c
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -140,14 +140,18 @@
 	struct dma_chan *chan = prtd->dma_chan;
 	struct dma_async_tx_descriptor *desc;
 	enum dma_transfer_direction direction;
+	unsigned long flags = DMA_CTRL_ACK;
 
 	direction = snd_pcm_substream_to_dma_direction(substream);
 
+	if (!substream->runtime->no_period_wakeup)
+		flags |= DMA_PREP_INTERRUPT;
+
 	prtd->pos = 0;
 	desc = dmaengine_prep_dma_cyclic(chan,
 		substream->runtime->dma_addr,
 		snd_pcm_lib_buffer_bytes(substream),
-		snd_pcm_lib_period_bytes(substream), direction);
+		snd_pcm_lib_period_bytes(substream), direction, flags);
 
 	if (!desc)
 		return -ENOMEM;
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 56ad923..a1d9b07 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -346,11 +346,10 @@
 		if (!memcmp(version, known_fw_versions + i, 4))
 			return 0;
 
-	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
-			"%02x %02x %02x %02x. "
+	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. "
 			"please reconnect to power. if this failure "
 			"still happens, check your firmware installation.",
-			version[0], version[1], version[2], version[3]);
+			4, version);
 	return -EINVAL;
 }
 
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4a469f0..561bb74 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -646,6 +646,8 @@
 			list_for_each(p, &chip->pcm_list) {
 				as = list_entry(p, struct snd_usb_stream, list);
 				snd_pcm_suspend_all(as->pcm);
+				as->substream[0].need_setup_ep =
+					as->substream[1].need_setup_ep = true;
 			}
  		}
 	} else {
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 2b9ffff..afa4f9e 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -92,6 +92,8 @@
 	unsigned char silence_value;
 	unsigned int stride;
 	int iface, alt_idx;
+	int skip_packets;		/* quirks for devices to ignore the first n packets
+					   in a stream */
 
 	spinlock_t lock;
 	struct list_head list;
@@ -105,6 +107,8 @@
 	int interface;	/* current interface */
 	int endpoint;	/* assigned endpoint */
 	struct audioformat *cur_audiofmt;	/* current audioformat pointer (for hw_params callback) */
+	snd_pcm_format_t pcm_format;	/* current audio format (for hw_params callback) */
+	unsigned int channels;		/* current number of channels (for hw_params callback) */
 	unsigned int cur_rate;		/* current rate (for hw_params callback) */
 	unsigned int period_bytes;	/* current period bytes (for hw_params callback) */
 	unsigned int altset_idx;     /* USB data format: index of alternate setting */
@@ -115,14 +119,13 @@
 
 	unsigned int hwptr_done;	/* processed byte position in the buffer */
 	unsigned int transfer_done;		/* processed frames since last period update */
-	unsigned long active_mask;	/* bitmask of active urbs */
-	unsigned long unlink_mask;	/* bitmask of unlinked urbs */
 
 	/* data and sync endpoints for this stream */
 	unsigned int ep_num;		/* the endpoint number */
 	struct snd_usb_endpoint *data_endpoint;
 	struct snd_usb_endpoint *sync_endpoint;
 	unsigned long flags;
+	bool need_setup_ep;		/* (re)configure EP at prepare? */
 
 	u64 formats;			/* format bitmasks (all or'ed) */
 	unsigned int num_formats;		/* number of supported audio formats (list) */
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index d6e2bb4..152bfd4 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -31,6 +31,7 @@
 #include "card.h"
 #include "endpoint.h"
 #include "pcm.h"
+#include "quirks.h"
 
 #define EP_FLAG_ACTIVATED	0
 #define EP_FLAG_RUNNING		1
@@ -170,6 +171,11 @@
 {
 	struct urb *urb = urb_ctx->urb;
 
+	if (unlikely(ep->skip_packets > 0)) {
+		ep->skip_packets--;
+		return;
+	}
+
 	if (ep->sync_slave)
 		snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
 
@@ -561,20 +567,19 @@
  * configure a data endpoint
  */
 static int data_ep_set_params(struct snd_usb_endpoint *ep,
-			      struct snd_pcm_hw_params *hw_params,
+			      snd_pcm_format_t pcm_format,
+			      unsigned int channels,
+			      unsigned int period_bytes,
 			      struct audioformat *fmt,
 			      struct snd_usb_endpoint *sync_ep)
 {
 	unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
-	int period_bytes = params_period_bytes(hw_params);
-	int format = params_format(hw_params);
 	int is_playback = usb_pipeout(ep->pipe);
-	int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) *
-							params_channels(hw_params);
+	int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
 
 	ep->datainterval = fmt->datainterval;
 	ep->stride = frame_bits >> 3;
-	ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
+	ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
 
 	/* calculate max. frequency */
 	if (ep->maxpacksize) {
@@ -687,7 +692,6 @@
  * configure a sync endpoint
  */
 static int sync_ep_set_params(struct snd_usb_endpoint *ep,
-			      struct snd_pcm_hw_params *hw_params,
 			      struct audioformat *fmt)
 {
 	int i;
@@ -730,7 +734,10 @@
  * snd_usb_endpoint_set_params: configure an snd_usb_endpoint
  *
  * @ep: the snd_usb_endpoint to configure
- * @hw_params: the hardware parameters
+ * @pcm_format: the audio fomat.
+ * @channels: the number of audio channels.
+ * @period_bytes: the number of bytes in one alsa period.
+ * @rate: the frame rate.
  * @fmt: the USB audio format information
  * @sync_ep: the sync endpoint to use, if any
  *
@@ -739,7 +746,10 @@
  * An endpoint that is already running can not be reconfigured.
  */
 int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
-				struct snd_pcm_hw_params *hw_params,
+				snd_pcm_format_t pcm_format,
+				unsigned int channels,
+				unsigned int period_bytes,
+				unsigned int rate,
 				struct audioformat *fmt,
 				struct snd_usb_endpoint *sync_ep)
 {
@@ -759,9 +769,9 @@
 	ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX);
 
 	if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL)
-		ep->freqn = get_usb_full_speed_rate(params_rate(hw_params));
+		ep->freqn = get_usb_full_speed_rate(rate);
 	else
-		ep->freqn = get_usb_high_speed_rate(params_rate(hw_params));
+		ep->freqn = get_usb_high_speed_rate(rate);
 
 	/* calculate the frequency in 16.16 format */
 	ep->freqm = ep->freqn;
@@ -771,10 +781,11 @@
 
 	switch (ep->type) {
 	case  SND_USB_ENDPOINT_TYPE_DATA:
-		err = data_ep_set_params(ep, hw_params, fmt, sync_ep);
+		err = data_ep_set_params(ep, pcm_format, channels,
+					 period_bytes, fmt, sync_ep);
 		break;
 	case  SND_USB_ENDPOINT_TYPE_SYNC:
-		err = sync_ep_set_params(ep, hw_params, fmt);
+		err = sync_ep_set_params(ep, fmt);
 		break;
 	default:
 		err = -EINVAL;
@@ -822,6 +833,8 @@
 	ep->unlink_mask = 0;
 	ep->phase = 0;
 
+	snd_usb_endpoint_start_quirk(ep);
+
 	/*
 	 * If this endpoint has a data endpoint as implicit feedback source,
 	 * don't start the urbs here. Instead, mark them all as available,
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index cbbbdf2..6376ccf 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -9,7 +9,10 @@
 					      int ep_num, int direction, int type);
 
 int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
-				struct snd_pcm_hw_params *hw_params,
+				snd_pcm_format_t pcm_format,
+				unsigned int channels,
+				unsigned int period_bytes,
+				unsigned int rate,
 				struct audioformat *fmt,
 				struct snd_usb_endpoint *sync_ep);
 
diff --git a/sound/usb/helper.c b/sound/usb/helper.c
index 9eed8f4..c1db28f 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -21,6 +21,7 @@
 
 #include "usbaudio.h"
 #include "helper.h"
+#include "quirks.h"
 
 /*
  * combine bytes and get an integer value
@@ -97,6 +98,10 @@
 		memcpy(data, buf, size);
 		kfree(buf);
 	}
+
+	snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype,
+			      value, index, data, size);
+
 	return err;
 }
 
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 4f40ba8..fe56c9d 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1267,6 +1267,13 @@
 		/* disable non-functional volume control */
 		master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);
 		break;
+	case USB_ID(0x1130, 0xf211):
+		snd_printk(KERN_INFO
+			   "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n");
+		/* disable non-functional volume control */
+		channels = 0;
+		break;
+
 	}
 	if (channels > 0)
 		first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize);
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index f782ce1..55e19e1 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -82,8 +82,7 @@
 /*
  * find a matching audio format
  */
-static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format,
-				       unsigned int rate, unsigned int channels)
+static struct audioformat *find_format(struct snd_usb_substream *subs)
 {
 	struct list_head *p;
 	struct audioformat *found = NULL;
@@ -92,16 +91,17 @@
 	list_for_each(p, &subs->fmt_list) {
 		struct audioformat *fp;
 		fp = list_entry(p, struct audioformat, list);
-		if (!(fp->formats & (1uLL << format)))
+		if (!(fp->formats & (1uLL << subs->pcm_format)))
 			continue;
-		if (fp->channels != channels)
+		if (fp->channels != subs->channels)
 			continue;
-		if (rate < fp->rate_min || rate > fp->rate_max)
+		if (subs->cur_rate < fp->rate_min ||
+		    subs->cur_rate > fp->rate_max)
 			continue;
 		if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) {
 			unsigned int i;
 			for (i = 0; i < fp->nr_rates; i++)
-				if (fp->rate_table[i] == rate)
+				if (fp->rate_table[i] == subs->cur_rate)
 					break;
 			if (i >= fp->nr_rates)
 				continue;
@@ -436,6 +436,42 @@
 }
 
 /*
+ * configure endpoint params
+ *
+ * called  during initial setup and upon resume
+ */
+static int configure_endpoint(struct snd_usb_substream *subs)
+{
+	int ret;
+
+	mutex_lock(&subs->stream->chip->shutdown_mutex);
+	/* format changed */
+	stop_endpoints(subs, 0, 0, 0);
+	ret = snd_usb_endpoint_set_params(subs->data_endpoint,
+					  subs->pcm_format,
+					  subs->channels,
+					  subs->period_bytes,
+					  subs->cur_rate,
+					  subs->cur_audiofmt,
+					  subs->sync_endpoint);
+	if (ret < 0)
+		goto unlock;
+
+	if (subs->sync_endpoint)
+		ret = snd_usb_endpoint_set_params(subs->data_endpoint,
+						  subs->pcm_format,
+						  subs->channels,
+						  subs->period_bytes,
+						  subs->cur_rate,
+						  subs->cur_audiofmt,
+						  NULL);
+
+unlock:
+	mutex_unlock(&subs->stream->chip->shutdown_mutex);
+	return ret;
+}
+
+/*
  * hw_params callback
  *
  * allocate a buffer and set the given audio format.
@@ -450,63 +486,33 @@
 {
 	struct snd_usb_substream *subs = substream->runtime->private_data;
 	struct audioformat *fmt;
-	unsigned int channels, rate, format;
-	int ret, changed;
+	int ret;
 
 	ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 					       params_buffer_bytes(hw_params));
 	if (ret < 0)
 		return ret;
 
-	format = params_format(hw_params);
-	rate = params_rate(hw_params);
-	channels = params_channels(hw_params);
-	fmt = find_format(subs, format, rate, channels);
+	subs->pcm_format = params_format(hw_params);
+	subs->period_bytes = params_period_bytes(hw_params);
+	subs->channels = params_channels(hw_params);
+	subs->cur_rate = params_rate(hw_params);
+
+	fmt = find_format(subs);
 	if (!fmt) {
 		snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n",
-			   format, rate, channels);
+			   subs->pcm_format, subs->cur_rate, subs->channels);
 		return -EINVAL;
 	}
 
-	changed = subs->cur_audiofmt != fmt ||
-		subs->period_bytes != params_period_bytes(hw_params) ||
-		subs->cur_rate != rate;
 	if ((ret = set_format(subs, fmt)) < 0)
 		return ret;
 
-	if (subs->cur_rate != rate) {
-		struct usb_host_interface *alts;
-		struct usb_interface *iface;
-		iface = usb_ifnum_to_if(subs->dev, fmt->iface);
-		alts = &iface->altsetting[fmt->altset_idx];
-		ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate);
-		if (ret < 0)
-			return ret;
-		subs->cur_rate = rate;
-	}
+	subs->interface = fmt->iface;
+	subs->altset_idx = fmt->altset_idx;
+	subs->need_setup_ep = true;
 
-	if (changed) {
-		mutex_lock(&subs->stream->chip->shutdown_mutex);
-		/* format changed */
-		stop_endpoints(subs, 0, 0, 0);
-		ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
-						  subs->sync_endpoint);
-		if (ret < 0)
-			goto unlock;
-
-		if (subs->sync_endpoint)
-			ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
-							  hw_params, fmt, NULL);
-unlock:
-		mutex_unlock(&subs->stream->chip->shutdown_mutex);
-	}
-
-	if (ret == 0) {
-		subs->interface = fmt->iface;
-		subs->altset_idx = fmt->altset_idx;
-	}
-
-	return ret;
+	return 0;
 }
 
 /*
@@ -537,6 +543,9 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_usb_substream *subs = runtime->private_data;
+	struct usb_host_interface *alts;
+	struct usb_interface *iface;
+	int ret;
 
 	if (! subs->cur_audiofmt) {
 		snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
@@ -546,6 +555,27 @@
 	if (snd_BUG_ON(!subs->data_endpoint))
 		return -EIO;
 
+	ret = set_format(subs, subs->cur_audiofmt);
+	if (ret < 0)
+		return ret;
+
+	iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface);
+	alts = &iface->altsetting[subs->cur_audiofmt->altset_idx];
+	ret = snd_usb_init_sample_rate(subs->stream->chip,
+				       subs->cur_audiofmt->iface,
+				       alts,
+				       subs->cur_audiofmt,
+				       subs->cur_rate);
+	if (ret < 0)
+		return ret;
+
+	if (subs->need_setup_ep) {
+		ret = configure_endpoint(subs);
+		if (ret < 0)
+			return ret;
+		subs->need_setup_ep = false;
+	}
+
 	/* some unit conversions in runtime */
 	subs->data_endpoint->maxframesize =
 		bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 79780fa..d73ac9b 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2781,6 +2781,59 @@
 	}
 },
 
+/* Microsoft XboxLive Headset/Xbox Communicator */
+{
+	USB_DEVICE(0x045e, 0x0283),
+	.bInterfaceClass = USB_CLASS_PER_INTERFACE,
+	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+		.vendor_name = "Microsoft",
+		.product_name = "XboxLive Headset/Xbox Communicator",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = &(const struct snd_usb_audio_quirk[]) {
+			{
+				/* playback */
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
+				.data = &(const struct audioformat) {
+					.formats = SNDRV_PCM_FMTBIT_S16_LE,
+					.channels = 1,
+					.iface = 0,
+					.altsetting = 0,
+					.altset_idx = 0,
+					.attributes = 0,
+					.endpoint = 0x04,
+					.ep_attr = 0x05,
+					.rates = SNDRV_PCM_RATE_CONTINUOUS,
+					.rate_min = 22050,
+					.rate_max = 22050
+				}
+			},
+			{
+				/* capture */
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
+				.data = &(const struct audioformat) {
+					.formats = SNDRV_PCM_FMTBIT_S16_LE,
+					.channels = 1,
+					.iface = 1,
+					.altsetting = 0,
+					.altset_idx = 0,
+					.attributes = 0,
+					.endpoint = 0x85,
+					.ep_attr = 0x05,
+					.rates = SNDRV_PCM_RATE_CONTINUOUS,
+					.rate_min = 16000,
+					.rate_max = 16000
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+
 {
 	/*
 	 * Some USB MIDI devices don't have an audio control interface,
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 2781726..0f58b4b 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -761,3 +761,27 @@
 	}
 }
 
+void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
+{
+	/*
+	 * "Playback Design" products send bogus feedback data at the start
+	 * of the stream. Ignore them.
+	 */
+	if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) &&
+	    ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
+		ep->skip_packets = 4;
+}
+
+void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
+			   __u8 request, __u8 requesttype, __u16 value,
+			   __u16 index, void *data, __u16 size)
+{
+	/*
+	 * "Playback Design" products need a 20ms delay after each
+	 * class compliant request
+	 */
+	if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) &&
+	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+		mdelay(20);
+}
+
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index 03e5e94..0ca9e91 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -1,6 +1,10 @@
 #ifndef __USBAUDIO_QUIRKS_H
 #define __USBAUDIO_QUIRKS_H
 
+struct audioformat;
+struct snd_usb_endpoint;
+struct snd_usb_substream;
+
 int snd_usb_create_quirk(struct snd_usb_audio *chip,
 			 struct usb_interface *iface,
 			 struct usb_driver *driver,
@@ -20,4 +24,10 @@
 int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
 				 struct audioformat *fp);
 
+void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep);
+
+void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
+			   __u8 request, __u8 requesttype, __u16 value,
+			   __u16 index, void *data, __u16 size);
+
 #endif /* __USBAUDIO_QUIRKS_H */